Sei sulla pagina 1di 276

Facoltà di Ingegneria Informatica

Utilizzo delle Trasformate


nella codifica delle immagini fisse, in movimento ed audio

Studente: Professore:
Francesco Bucciantini Dottor Andrea Tortorelli

Peer Review:
Dottor Ingegner Carlo Gimelli / Dottor Gianfranco Geria / Livio Aloja

Si ringraziano
il Dottor Ingegner Tiziano Squarcia ed il Dottor Paolo Casati

ANNO ACCADEMICO 2020-2021


– Indice:
– Introduzione...............................................................................................................3
– 0) Cenni storici ed importanza della compressione video..........................................3
– 1) Basi della codifica tramite trasformata..............................................................5
– 1.1) Trasformate unitarie...................................................................................................6
– 1.2) Trasformate ad una dimensione (monodimensionali) ........................................................7
– 1.3) Trasformate a due dimensioni (bidimensionali) ................................................................8
– 1.4) Trasformate a tre dimensioni (tridimensionali) .................................................................9
– 1.5) Trasformate direzionali...............................................................................................9
– 1.6) Analisi del funzionamento di alcune trasformate prese in esame .......................................10
– Trasformata di Karhunen-Loève...........................................................................................10
– Trasformata Discreta di Fourier............................................................................................11
– Trasformata Discreta del Coseno..........................................................................................12
– Trasformata di Walsh Hadamard..........................................................................................14
– Trasformata Discreta di Wavelet...........................................................................................14
– 2) Utilizzo delle trasformate nei codec di codifica delle immagini....................16
– 2.1) Lo standard JPEG...................................................................................................16
– 2.2) Lo standard JPEG2000............................................................................................19
– 2.3) Lo standard GIF......................................................................................................22
– 2.4) Lo standard PNG....................................................................................................28
– 2.5) SSIM – Una metrica oggettiva per comparare la qualità ..................................................50
– 3.0) Basi della codifica video................................................................................52
– 3.0.1) Scene video naturali.............................................................................................52
– 3) Utilizzo delle trasformate nei codec di codifica video....................................61
– Generalizzazione su encoder e decoder............................................................................61
– 3.1) H.261...................................................................................................................62
– 3.2) Video Standard, MPEG-1.........................................................................................66
– 3.3) Video Standard, MPEG-2.........................................................................................69
– 3.4) Video Standard, H.263............................................................................................71
– 3.5.0) Video Standard, MPEG-4......................................................................................72
– 3.5.1) Video Standard, MPEG-4 Visual (MPEG-4 Part 2)......................................................73
– 3.5.2) Video Standard, MPEG-4 (Part 10), AVC H.264 .........................................................77
– 3.6.0) Introduzione all'HEVC – H.265..............................................................................130
– 3.6.1) Una trasformata adattiva per la codifica video migliorata basata sull'H.264 .....................130
– 3.6.2) Architettura........................................................................................................131
– 3.6.3) Dettagli della trasformata adattiva ..........................................................................132
– 3.6.4) Valutazione delle prestazioni.................................................................................138
– 3.7) HEVC – H.265......................................................................................................139
– 3.8) VVC – H.266........................................................................................................150
– 3.9) Comparazione MPEG-1 vs MPEG-2 vs MPEG-4 Visual vs H.265 vs H.266 .......................243
– 4) Utilizzo delle trasformate nei codec di codifica audio.................................249
– 4.1) MPEG-1 Layer 1 (.mp1).........................................................................................258
– 4.2) MPEG-1 Layer 2 (.mp2).........................................................................................259
– 4.3) MPEG-1 Layer 3 (.mp3).........................................................................................260
– 4.4) Advanced Audio Coding (AAC)................................................................................261
– 4.5) AC3 – Audio Coding 3............................................................................................265
– 4.6) Vorbis (.ogg)........................................................................................................267
– 4.7) Opus (.opus)........................................................................................................268
– 4.8) I codec audio lossless: FLAC e WAV a confronto .........................................................270
– Valutazioni finali della tesi......................................................................................274
– Bibliografia.............................................................................................................275

Introduzione:
La tesi si basa sull'analisi delle tecnologie di codifica in un particolare metodo di compressione:
la codifica mediante trasformata.
Tale metodo di codifica è basato sul rimuovere la ridondanza spaziale presente in una data
immagine (che sia singola o parte di un video – frame – ) trasformandola dal dominio spaziale a
quello delle frequenze.
Il metodo di codifica preso in esame trae vantaggio dal fatto che l'occhio umano percepisce in modo
minore le alte frequenze rispetto alle basse frequenze in modo da poter tagliare dettagli meno
significativi a livello di percezione visiva.
Ad oggi, quasi tutti i più conosciuti ed utilizzati metodi di codifica utilizzano la DCT (Discrete
Cosine Trasform) ovvero la Trasformata Discreta del Coseno, tuttavia esistono nuovi metodi di
codifica che utilizzano diversi tipi di trasformata e che hanno dato vita ad approcci alternativi.
Lo scopo della tesi è di analizzare nel dettaglio la nuova codifica video H.266, la codifica audio ed i
vari metodi di trasformata utilizzabili, nonché comparare i risultati dei precedenti metodi di codifica
ed i diversi tipi di trasformata utilizzata da ognuno di essi in modo completo e dettagliato.
Come introduzione alle codifiche video, inoltre, verranno esplicati i vari metodi di codifica delle
immagini fisse, con particolare importanza rivolta allo standard lossless PNG ed, infine, verranno
analizzati anche i codec audio.

0) Cenni storici ed importanza della compressione video


La velocità delle connessioni internet è in continuo aumento, così come i bitrate dei network e la
grandezza di Hard Disk, memorie flash e media ottici.
Con il prezzo delle trasmissioni e dell'archiviazione in continua diminuzione, potrebbe non essere
immediatamente chiaro perché la compressione video è tanto necessaria e perché ci sono così tanti
sforzi – ora come in passato – per renderla migliore.
La compressione video ha due importanti benefici: il primo è che rende possibile utilizzare video
digitali nelle trasmissioni e nello storage in ambienti che non sono in grado di supportare video non
compressi, chiamati “raw”.
Ad esempio, per quanto possa essere veloce, la fibra ottica che raggiunge le attuali abitazioni è
ancora insufficiente per poter gestire video non compressi in tempo reale (anche a bassi frame rate –
immagini al secondo – e basse risoluzioni).
Un altro esempio è che sia i DVD che i Bluray Disk sono in grado di contenere solo pochi frame (e
dunque pochi minuti) di un video raw conforme alle qualità ed ai frame rate degli standard televisivi
e sarebbero dunque inutilizzabili senza un'opportuna compressione video.
Il secondo beneficio offerto dalla compressione video è che permette un utilizzo più efficiente delle
risorse di trasmissione e storage.
Un segnale può dunque essere compresso rimuovendo la ridondanza e ci sono due metodi principali
di compressione: il metodo lossless e quello lossy.
Nelle compressioni lossless (prive di perdita) la ridondanza statistica è rimossa in modo che il
segnale originale possa essere perfettamente ricostruito dal decoder.
Sfortunatamente, al momento, i metodi di codifica lossless riescono a comprimere le immagini in
modo insufficiente e, mentre per la codifica delle immagini fisse è molto utilizzata la codifica
lossless, non è possibile affermare la stessa cosa per la codifica video.
I più comuni metodi di compressione video infatti sono basati su compressioni lossy (con perdita),
nelle quali è possibile ottenere grandi benefici in termini di compressione,
al costo però di perdere parte delle informazioni; difatti l'immagine ricostruita dal decoder non sarà
mai identica a quella originale.
L'obiettivo dei codec di codifica video è dunque quello di ottenere il massimo beneficio in termini
di compressione, con la minima distorsione introdotta dal processo di compressione.
Gli algoritmi di compressione video rimuovono la ridondanza temporale, spaziale e/o i domini di
frequenza.
Come prima introduzione, si guardi ora l'immagine sottostante che rappresenta un esempio di un
singolo frame video.

All'interno delle regioni evidenziate (rettangolo di sinistra e destra) è presente una lieve variazione
nel contenuto dell'immagine e, quindi, c'è una ridondanza spaziale significativa.
Si prenda ora in analisi la seconda immagine riportata di seguito.

Questa seconda immagine mostra lo stesso identico frame dopo essere stato processato da un filtro
passa-basso in modo da rimuovere alcuni dei contenuti ad alta frequenza.
L'occhio umano è più sensibile alle basse frequenze e l'immagine è ancora riconoscibile, sebbene
parte delle informazioni sono andate perdute (si pensi alle linee del muro sullo sfondo).
Si prenda ora in esame questa terza immagine che mostra il frame successivo della sequenza video.

La sequenza originale era stata catturata da una videocamera a 25 fps, quindi c'è un piccolo
cambiamento tra i due frame e c'è una chiara ridondanza temporale (la maggior parte dell'immagine
rimane identica tra i frame successivi).
Rimuovendo i diversi tipi di ridondanza (spaziale, delle frequenze e/o temporale), è possibile
comprimere i dati al costo di una perdita di informazioni (distorsione).
Un'ulteriore compressione può essere raggiunta encodando i dati processati utilizzando una codifica
entropica come quella di Huffman.
La compressione video e delle immagini rappresenta da anni un prolifico campo di ricerca e sono
stati sviluppati numerosi sistemi ed algoritmi di compressione e decompressione e sono stati definiti
numerosi standard.
Dopo questa breve introduzione, passiamo adesso ad analizzare le fondamenta sulle quali si basa la
codifica mediante trasformata per poi introdurre i primi standard di codifica delle immagini fisse.

1) Basi della Codifica Tramite Trasformata


La codifica tramite trasformata è uno degli strumenti fondamentali della codifica audio e video che
utilizziamo oggi giorno in quasi ogni settore.
Il suo funzionamento è da ricondurre al processo di riduzione di ridondanza spaziale rappresentando
i pixel nel dominio delle frequenze per poi poter effettuare una riduzione della quantità di dati in
uscita tramite compressione e quantizzazione.
Per poter essere compresso, un segnale deve essere decorellato tramite una trasformata apposita,
ridistribuendo la sua energia ad un piccolo numero di coefficienti,
collocati nella regione delle basse frequenze.
Questi coefficienti possono essere quantizzati in modo da poter eliminare una piccola quantità di
informazioni meno rilevanti senza intaccare la qualità finale dell'immagine una volta ricostruita.
Sebbene il processo di trasformata non comporti una perdita di dati (cioè è “lossless”), il processo
di quantizzazione la comporta e viene dunque detto “lossy” - cioè “con perdita”; si ha così quello
che viene chiamato un “errore di quantizzazione” in quanto non è più possibile accedere ai dati
originali una volta quantizzati.
Ad ogni modo, non è del tutto corretto dire che il processo di trasformata è privo di perdita, poiché,
sebbene lo sia in teoria, in pratica può comportare una limitazione in quanto la sua implementazione
può avere dei limiti numerici dovuti al suo stesso impiego, quali, ad esempio, arrotondamenti e
troncamenti.
Il segnale viene segmentato in blocchi pari, tipicamente da 8x8.
Ogni blocco è poi trasformato individualmente mediante l'operazione di “transformazione dei
macroblocchi”.
Grazie a questo processo basato sui blocchi, è possibile ridurre la complessità totale dei calcoli di
trasformata in quanto risulta molto più facile eseguire i blocchi individualmente rispetto che a
processare tale operazione sull'intera immagine.
Trasformare ogni blocco singolarmente può inoltre catturare le informazioni in modo migliore,
sfruttando la correlazione tra di essi in modo migliore, anche se, in realtà, tale correlazione non è
mai veramente sfruttata a dovere e spesso questo può risultare in errori di riproduzione dovuti alla
ricostruzione finale dell'intera immagine.
Un esempio è dato da un'immagine fortemente quantizzata nella quale è possibile notare artefatti
dovuti a “blocking”, ovvero è possibile notare con facilità i bordi dei vari blocchi.
In altre parole: maggiore è la compressione, più facile sarà vedere tali artefatti.
Dal punto di vista teorico, una trasformata è tenuta a soddisfare alcuni punti fondamentali in modo
da rendere la sua adozione utile al fine pratico.
Il primo dei requisiti fondamentali è la “reversibilità”, ovvero il fatto che il segnale di ingresso
possa essere ricostruito senza errori dal segnale di uscita al quale è stato applicato il calcolo di
trasformata.
Questo è forse il più importante dei requisiti - almeno per quanto riguarda la codifica video - in
quanto per poter visualizzare un'immagine è necessario poter ricreare il segnale di partenza.
Un altro elemento riguarda la riduzione della quantità di dati, ovvero il fatto che la trasformata
debba concentrare il segnale in entrata nel minor numero possibile di coefficienti.
Importante è anche il fatto che la stessa informazione non deve essere ripetuta in coefficienti
diversi, o, se ciò accade, la ripetizione deve essere ridotta al minimo in modo da assicurare
un'efficiente decorrelazione.
Idealmente, possiamo dire che, oltre alle cose sopraelencate, una trasformata debba essere anche il
meno complessa possibile (parlando in termini di operazioni da eseguire) in quanto è logico pensare
che meno calcoli vengono eseguiti, maggiore sarà la sua efficienza a livello di calcolo
computazionale.

1.1) Trasformate Unitarie:

Una trasformata unitaria di un dato vettore x in ingresso è definita da:

Dove B è una matrice unitaria pari ed y è il vettore con i coefficienti di trasformata.


Una matrice pari è unitaria se il suo inverso è uguale al suo trasposto coniugato.
Se una matrice unitaria ha solo valori reali, allora la sua inversa sarà uguale al suo coniugato
e viene definita “matrice ortogonale”.
Ricordo che i vettori colonna ed i vettori riga di una matrice unitaria sono ortogonali
(perpendicolari tra loro) e normalizzati e possono essere definiti come segue:
dove b di k è la k 'esima colonna della matrice unitaria B.
I vettori b di k costituiscono un gruppo di vettori base ortonomali.
I vettori base sono un gruppo di vettori che possono essere combinati linearmente per rappresentare
ogni vettore in un dato spazio vettoriale.
A sua volta, le funzioni base sono un gruppo di funzioni che possono essere combinate linearmente
per rappresentare ogni funzione in un dato spazio di funzione.
In questo caso, la matrice unitaria B rappresenta la trasformata unitaria di funzione base.
Le trasformate unitarie comprendono le caratteristiche sopraelencate tra cui, in primis,
la reversibilità; in questo caso abbiamo che:

Un'altra proprietà di quelle sopraelencate che viene rispettata è quella della riduzione della quantità
di dati tramite i coefficienti ed il fatto di preservare l'energia dell'onda mediante gli stessi:

Le trasformate unitarie, solitamente, sono le più utilizzate negli standard di compressione video.

1.2) Trasformate ad Una Dimensione (monodimensionali):

Considerando x(n) un blocco di N campioni in entrata (dominio spaziale) ed y(k) un gruppo di N


coefficienti di trasformata (dominio delle frequenze), una trasformata monodimensionale è data da:

dove a(k,n) sono le funzioni di trasformata base.


La trasformata inversa usata per ricomporre il segnale originale è invece definita da:

dove b(k,n) sono le funzioni di trasformata base inversa.


Tenendo conto che il primo vettore base tipicamente corrispondente alla frequenza di componente
zero, corrisponde alla funzione costante, allora y(0) è chiamato coefficiente DC, che rappresenta il
principale indicatore della forma d'onda sotto trasformata.
È proprio questo il coefficiente di trasformata più importante dato che è associato alla frequenza più
bassa percepibile.
Tutti gli altri coefficienti, invece, sono chiamati coefficienti AC.
1.3) Trasformate a Due Dimensioni (bidimensionali):

Considerando ora x(m,n) come blocco di campioni NxN a due dimensioni e y(k,l) un gruppo di NxN
coefficienti di trasformata, la trasformata bidimensionale è data da:

La trasformata bidimensionale inversa è invece data da:

a(k,l,m,n) e b(k,l,m,n) sono rispettivamente le funzioni di trasformata bidimensionale e trasformata


bidimensionale inversa.
Ci sono due classi fondamentali di trasformate bidimensionali: le trasformate separabili e le
trasformate non separabili.
Le trasformate non separabili sono calcolate utilizzando semplicemente le N colonne in ingresso da
un capo all'altro per formare una singola colonna di vettori di lunghezza N^2 e solo dopo viene
effettuato il calcolo di trasformata.
Le trasformate separabili sfruttano sia le correlazioni orizzontali che quelle verticali del segnale in
ingresso e, tipicamente, richiedono un'operazione aritmetica N^4.
In una trasformata separabile bidimensionale, entrambe le funzioni di trasformata di base sono
separate in operazioni distinte (orizzontale e verticale):

Con queste due operazioni, una trasformata separabile bidimensionale può essere elaborata in due
fasi indipendenti, eseguite una dopo l'altra.
La prima fase utilizza la funzione base orizzontale ah (l,n),
sfruttando la correlazione orizzontale dei dati.
La seconda fase utilizza invece la funzione di base verticale av (k,m),
sfruttando la correlazione verticale dei dati.
Le trasformate bidimensionali separabili sono implementate come due trasformate
monodimensionali consecutive e sono date da:

In notazione di matrice abbiamo:

Le funzioni di base simmetriche sono funzioni che hanno componenti orizzontali e verticali
simmetriche Av = Ah = A. In questo caso, abbiamo:
La moltiplicazione di due matrici NxN richiede un'operazione matematica di N^3.
Di conseguenza, una trasformata separabile bidimensionale, che ha due moltiplicazioni di matrice,
richiede un'operazione 2N^3 (ricordo che la trasformata non separabile richiede N^4).
Quindi, nel caso in cui si abbia N > 2, è preferibile utilizzare una trasformata bidimensionale.

1.4) Trasformate a Tre Dimensioni (tridimensionali):

Consideriamo adesso x(m,n,p) come un blocco di campioni NxNxN tridimensionale in ingresso.


Tale segnale d'ingresso ha due componenti spaziali ed una componente temporale.
Considerando y(k,l,q) i coefficienti di trasformata, la trasformata tridimensionale è data da:

La trasformata tridimensionale inversa è invece data da:

a(k,l,q,m,n,p) e b(k,l,q,m,n,p) sono rispettivamente le funzioni di trasformata tridimensionale e


trasformata tridimensionale inversa.
Con una trasformata tridimensionale è possibile sfruttare la correlazione tra i dati in tre dimensioni:
due nello spazio ed uno nel tempo.
In particolare, nella codifica video, è possibile rimuovere non solo la ridondanza spaziale,
ma anche la ridondanza temporale!
Ovviamente, utilizzando questo tipo di trasformata, la durata di codifica subirà un significativo
rallentamento, soprattutto su video con un elevato numero di frame.

1.5) Trasformate Direzionali

Una trasformata direzionale è una trasformata che utilizza le informazioni dei bordi presenti in
alcuni dati in entrata per poter sfruttare meglio la correlazione dei gruppi di dati.
Lo scopo di questa trasformata è di aumentare la compressibilità rilevando e rimuovendo la
ridondanza spaziale in modo migliore rispetto alle trasformate non direzionali,
aumentando così il rapporto di compressione rispetto alle stesse.
Le trasformate bidimensionali – come ho detto prima – sono processate individualmente calcolando
due trasformate monodimensionali (una verticale ed una orizzontale).
Tale approccio può risultare molto utile in alcuni casi, ma non è sempre possibile applicarlo
ottenendo il risultato sperato in tutte le situazioni.
Consideriamo il seguente blocco che ha la peculiarità di avere una linea diagonale che divide due
regioni.

In questo caso, una trasformata bidimensionale separabile genererebbe un numero più elevato di
coefficienti non nulli, deteriorando così l'efficienza di compressione della trasformata stessa.
È proprio in questo caso che ci vengono in aiuto le trasformate direzionali.
Le trasformate direzionali sono varie e possono avere approcci e risultati diversi l'una dall'altra a
causa del loro modus operandi.
Ci sono le trasformate direzionali dipendenti dal modo che possono utilizzare diverse funzioni base,
ognuna per un bordo specifico.
Dopo aver analizzato la direzione dei bordi, selezionano quale funzione base utilizzare ed effettuano
una trasformata bidimensionale.
Ci sono le trasformate direzionali a singola dimensione ripetuta.
Nella prima fase, viene eseguita una trasformata monodimensionale sulla direzione del bordo.
Nella seconda fase, viene effettuata una trasformata monodimensionale orizzontale.
Ci sono infine le trasformate direzionali di ordinamento e bidimensionali.
In questo caso, i gruppi di dati in ingresso vengono riordinati a seconda del bordo direzionale.
Dopodiché, viene eseguita una trasformata monodimensionale per le righe e per le colonne,
similmente a quanto accade in un processo di trasformata bidimensionale.

1.6) Analisi del funzionamento di alcune trasformate prese in esame

Dopo una breve introduzione sui tipi di trasformata, procedo ora col prendere in esame le
trasformate più importanti utilizzate per la codifica video.

– Trasformata di Karhunen-Loève

La Trasformata di Karhunen-Loève (KLT) è una trasformata unitaria ortogonale non separabile,


la cui trasformata monodimensionale e la sua inversa monodimensionale per un vettore x sono
definite da:

La matrice Φ rappresenta la funzione di trasformata di Karhunen-Loève di base.


Questa trasformata non ha un insieme di funzioni base predefinite poiché le sue funzioni base sono
dipendenti dal dato di origine e sono determinate nel seguente modo:

Covarianza: la covarianza della matrice Σ è definita come


dove

è il valore dell'i-esimo dato in ingresso nel vettore x.

Autovettori ed Autovalori della covarianza computazionale della matrice: computazione della


matrice Φ degli autovettori della matrice di covarianza Σ

dove Λ è la matrice diagonale di autovalori della matrice di covarianza Σ

dove λm è l'm-esimo autovalore della matrice di covarianza Σ. Le colonne della matrice Φ


corrispondono agli autovettori della matrice di covarianza Σ, rappresentata nelle funzioni di base
della trasformata di Karhunen-Loève.
Questa trasformata è la miglior trasformata possibile in termini di compressione in quanto riesce a
codificare il segnale utilizzando il minor numero di coefficienti possibile.
Ad ogni modo, la trasformata di Karhunen-Loève utilizza delle funzioni di base dipendenti dal dato
di ingresso, il che comporta la continua computazione della matrice di covarianza del segnale in
ingresso, così come la sua memorizzazione e trasmissione.
Non solo, proprio per ottenere una codifica tanto efficiente, la trasformata di Karhunen-Loève
richiede una grande quantità di calcoli per poter determinare le funzioni di base,
il che ne aumenta la complessità.
Proprio a causa della grande quantità di calcoli richiesti, il suo utilizzo nell'ambito della codifica
video è limitato, anche se in passato era stata proposta (e non accettata) per l'H.265 HEVC.

– Trasformata Discreta di Fourier

La Trasformata Discreta di Fourier (DFT) è una trasformata unitaria ed ortogonale che è utilizzata
per scomporre il dato originale nelle sue componenti di seno e coseno.
È una trasformata unitaria bidimensionale e la sua trasformata ed inversa (per un blocco di dati
NxN) sono definite da:

Le funzioni base della trasformata discreta di Fourier corrispondono alle onde di seno e coseno con
frequenze in aumento.
Il primo coefficiente y(0,0) rappresenta i componenti DC.
A differenza di quella di Karhunen-Loève, quella di Fourier è una trasformata separabile e le sue
funzioni di base possono essere rappresentate come prodotti di due trasformate unitarie date da:
Per un vettore di lunghezza N, computare una trasformata di fourier monodimensionale richiede
N^2 operazioni aritmetiche.
Per ridurre la complessità di questa trasformata, spesso viene utilizzata un'implementazione speciale
chiamata “Trasformata Discreta di Fourier Veloce” (FFT).
Utilizzando la FFT al posto della DFT normale, è possibile ridurre le operazioni aritmetiche per la
trasformata monodimensionale ad un semplice NlogN.
La trasformata Discreta di Fourier Veloce è dunque in grado di ridurre significativamente la
complessità della Trasformata Discreta di Fourier normale ed il fatto di poter contare su una
versione “veloce” della stessa è senza dubbio un grande vantaggio rispetto alla trasformata di
Karhunen-Loève.
Ad ogni modo, la FFT ha un grande difetto che è quello di produrre nella codifica dei coefficienti
complessi (cioè con parti reali ed immaginarie) e quindi difficili da gestire, salvare e manipolare.
Viene in aiuto, in questo caso, la DCT cioè la Trasformata Discreta del Coseno (della quale parlerò
di seguito) che utilizza valori reali e non numeri complessi.

– Trasformata Discreta del Coseno

La Trasformata Discreta del Coseno (DCT) è una trasformata unitaria ortogonale concettualmente
simile a quella di Fourier (DFT) ma con il vantaggio di utilizzare solamente numeri reali (e non
complessi come quella di Fourier).
La trasformata bidimensionale per un blocco NxN è definita da:

e la sua inversa è data da:

con

Come per la trasformata Discreta di Fourier, la trasformata Discreta del Coseno può essere
rappresentata come prodotto di due trasformate monodimensionali, visto che è anch'essa una
trasformata separabile.

~ DFT e DCT a confronto

In questo grafico prendo come modello una funzione base da 8x8 sia per la Trasformata Discreta di
Fourier che per la Trasformata Discreta del Coseno, onde evidenziarne il differente funzionamento:
Trasformata Discreta di Fourier (DFT) 8x8 Trasformata Discreta del Coseno (DCT)

Dato che la funzione coseno è reale e pari cos(x) = cos(-x) ed il segnale in ingresso è anch'esso
reale, la trasformata Discreta del Coseno inversa genera una funzione pari periodica in 2N,
considerando N la lunghezza della sequenza del segnale originale.
La trasformata Discreta di Fourier inversa, invece, produce un segnale ricostruito che è periodico in
N.
La trasformata Discreta del Coseno, inoltre, introduce delle discontinuità molto più lievi di quella di
Fourier e gli errori di ricostruzione ai bordi dei blocchi sono più piccoli, di conseguenza gli artefatti
da compressione (blocking) sono meno pesanti di quelli della trasformata Discreta di Fourier.

Dall'illustrazione è facile notare come la DFT sia periodica in N e la DCT sia periodica in 2N.
Il che significa che, nella DFT, ci sono delle discontinuità tra N ed N nei punti di bordo che sono
invece evitate nella DCT.
Per quanto concerne i segnali altamente correlati, la DCT ha dei risultati di codifica molto simili
alla trasformata di Karhunen-Loève.
Ad ogni modo, a differenza di quest'ultima, le funzioni di base della DCT non sono dipendenti dai
dati in ingresso, favorendone così, ancora una volta, l'utilizzo.
La DCT, inoltre, così come la DFT, ha una versione “veloce” chiamata “Trasformata Discreta del
Coseno Veloce”.
La versione “veloce” riduce i calcoli aritmetici per una trasformata monodimensionale per un
vettore di lunghezza N a solo NlogN, esattamente come per la trasformata Discreta di Fourier
Veloce.
Grazie a tutte queste peculiarità, la Trasformata Discreta del Coseno è diventata la trasformata di
riferimento per codifiche come il JPEG, l'H.264 e l'MPEG-2 nel quale la DCT bidimensionale viene
effettuata su blocchi da 8x8 ed in seguito viene effettuata una quantizzazione dei suoi coefficienti.
Per quanto riguarda l'H.264 AVC, però, questi non si serve solamente della DCT, bensì esegue una
“seconda passata” per mezzo di un'altra trasformata: la trasformata di Walsh-Hadamard,
che illustrerò di seguito.

– Trasformata di Walsh-Hadamard

La trasformata di Walsh-Hadamard è una trasformata unitaria ed ortogonale.


È una trasformata separabile e la sua trasformata ed inversa monodimensionali per un vettore x
di lunghezza 2^m sono definite da:

dove la matrice Hm rappresenta la funzione di base della WHT.


La matrice Hm è una matrice di Hadamard da 2^m x 2^m, ovvero una matrice quadrata i cui valori
di ingresso possono essere sia +1 che -1 e le cui righe sono reciprocamente ortogonali ed è data da:

in cui 1 su radice di due è il fattore normalizzante.


La trasformata di Walsh-Hadamard, così come le precedenti due, possiede una sua versione
“veloce”, chiamata “Trasformata di Walsh-Hadamard Veloce”.
Così come per le altre sopraelencate, la versione “veloce” di questa trasformata può ridurre il
numero di operazioni aritmetiche per una trasformata monodimensionale da N^2 a NlogN.
La trasformata di Walsh-Hadamard lavora con matrici puramente reali, contenendo valori di +1 e -
1; così facendo, le operazioni che deve compiere sono limitate a calcoli molto semplici e,
soprattutto per la sua versione “veloce”, è la trasformata col più basso livello di complessità.
Ad ogni modo, proprio per la semplicità dei calcoli che effettua, la sua capacità di compressione è
altrettanto modesta, per questo il suo utilizzo autonomo è pressoché nullo nel campo della codifica
video, ma – come ho detto prima – è molto importante in quanto viene associata alla DCT per poter
ottenere una miglior compressione nel codec H.264 AVC.

– Trasformata Discreta di Wavelet

La trasformata Discreta di Wavelet è una trasformata unitaria, ortogonale e separabile che di solito è
applicata all'intero dato in ingresso e non a dei piccoli blocchi come invece accadeva per le
trasformate viste in precedenza.
La DWT di un segnale in ingresso x è eseguita passandolo attraverso vari filtri.
Per prima cosa, il segnale in entrata è decomposto usando un filtro passa basso, ovvero un filtro che
passa le basse frequenze ed attenua le alte frequenze, dopodiché viene processato da un filtro passa
alto che passa le alte frequenze ed attenua le basse frequenze.
Tale operazione è effettuata utilizzando:
dove ylow and yhigh sono rispettivamente i coefficienti di banda passa basso e passa alto.
I filtri g ed h devono essere in stretto rapporto tra loro per poter dividere il segnale in ingresso in
due bande, formando così un filtro di quadratura a specchio:

dove f è la frequenza.
Tale proprietà assicura che non ci sia alcuna perdita di informazioni durante il processo di
decomposizione.
Con l'operazione di filtraggio passa basso e passa alto, metà delle frequenze del segnale sono
rimosse in entrambe le bande.
In questo modo, è possibile utilizzare il teorema di campionamento:
se una funzione x(f) contiene frequenze che sono più piccole di B hertz, allora è determinata dando
le sue ordinate ad una serie di punti distanziati 1/(2B) secondi.
Metà dei campioni possono essere tagliati e l'output dei due filtri (g ed h) può essere
sotto-campionato per due. Tale operazione è data da:

Dopo questo processo, la maggior parte dell'energia è generalmente concentrata nella banda passa
basso.
Per poter aumentare la frequenza di risoluzione in questa banda, possono essere eseguite più
decomposizioni, ripetendo l'operazione di sopra.
Per un segnale in ingresso monodimensionale, le applicazioni successive dei filtri sull'output passa
basso risultano in una scomposizione dinamica, ovvero il numero di coefficienti per ogni nuova
banda bassa è metà del numero della scomposizione precedente.
Per un segnale in ingresso bidimensionale, il numero dei coefficienti di ogni nuova banda bassa è
un quarto del numero della scomposizione precedente.
La trasformata Discreta di Wavelet ha la peculiarità di possedere coefficienti in grado di ricostruire
varie risoluzioni spaziali.
Così come per le altre trasformate sopraelencate, la trasformata Discreta di Wavelet ha la sua
versione “veloce” chiamata “Trasformata Discreta di Wavelet Veloce” e può eseguire una
trasformata monodimensionale per un vettore di lunghezza N in sole N operazioni aritmetiche.
Tra i pregi della Trasformata Discreta di Wavelet ci sono l'assenza di blocking come artefatto da
compressione (questo perché viene applicata all'intera immagine e non a blocchi), sfrutta la
correlazione di tutti i blocchi vicini (visto che viene applicata a tutta l'immagine) consentendo alti
livelli di compressione ed ha una decomposizione dinamica ed è quindi possibile aumentare o
diminuire la risoluzione spaziale dei dati recuperati semplicemente aumentando o diminuendo il
numero dei coefficienti decodificati.
L'unico problema è che processare l'intera immagine assieme invece di dividerla in blocchi richiede
un alto carico computazionale dal punto di vista dei calcoli.
La trasformata Discreta di Wavelet è utilizzata nello Standard JPEG 2000 di cui parlerò di seguito.
2) Utilizzo delle Trasformate nei codec di codifica immagini
Al fine di esplicare l'utilizzo dei metodi di codifica all'interno dei codec video, è preferibile
affrontare prima il loro impiego nei codec di codifica di immagini statiche in quanto più semplici.
Inoltre, in questo capitolo viene rappresentato passo per passo l'utilizzo dei metodi di trasformata
visti sopra in un contesto reale e di utilizzo pratico.

2.1) Lo Standard JPEG

Lo standard JPEG utilizza due tipi di codifica: lossy (con perdita) e lossless (privo di perdita); nel
secondo caso, inoltre, non viene effettuata una codifica tramite trasformata.
È doveroso dire, comunque, che la codifica lossless è molto meno efficiente in termini di
compressione rispetto a quella lossy che, però, comporta la perdita di una parte di informazione.
Non solo, non è sempre detto che il metodo di compressione lossless riesca sempre a ridurre la
dimensione finale del file e potrebbero esserci casi in cui questo risulta essere addirittura più grande
del file di partenza!
In tale caso, quindi, è preferibile optare per lasciare il file originale invariato al posto di tenere
quello processato dalla codifica lossless.
Generalmente, il metodo più utilizzato è quello lossy ed è proprio questo a cui darò più importanza.
La trasformata utilizzata dal JPEG nella codifica lossy è la trasformata discreta del coseno
bidimensionale, unitaria, ortogonale e separabile ed è data da:

dove y(k,l) è il coefficiente alle coordinate (k,l) e x(m,n) è il valore di ingresso (di chroma –
componente del colore – e luma – immagine in bianco e nero in sé per sé) alle coordinate (m,n).

Il JPEG utilizza dunque la Trasformata Discreta del Coseno per la sua implementazione e procede
nella codifica nel seguente modo:

1) L'immagine originale viene divisa in blocchi da 8x8.


2) Ogni blocco da 8x8 viene trasformato utilizzando un'operazione di trasformata Discreta del
Coseno bidimensionale (cioè, rappresentandolo in un'opportuna base dello spazio
vettoriale); il risultato è dato da 8x8 coefficienti (quindi 64) creati dalla DCT stessa.
3) Tutti i 64 coefficienti creati dalla DCT sono poi quantizzati utilizzando una specifica matrice
di quantizzazione.
4) I coefficienti DCT quantizzati vengono organizzati in una sequenza monodimensionale a
“zig zag”.
Grazie a questa particolare sequenza, l'encoder incontrerà tutti i coefficienti DCT non nulli
del blocco il più velocemente possibile.
Non solo, dato che tale ordine corrisponde (molto approssimativamente) ad una lista
ordinata dei coefficienti di percezione visiva, il suo impiego fa sì che i coefficienti più
importanti dal punto di vista visivo siano sempre trasmessi prima di quelli meno importanti.
Dopodiché, il JPEG crea una coppia (run, level) per ogni coefficiente.
Il “run” è la quantità di coefficienti DCT nulli che precedono i veri coefficienti che vengono
codificati nella sequenza a “zig zag”.
Il “level” è la grandezza quantizzata dei coefficienti per essere codificati.
Il “run” ed il numero di bit utilizzati per codificare il “level” sono poi codificati utilizzando
la codifica di Huffman ed il “level” è codificato utilizzando il VLI (Variable Length Integer).
Per sfruttare meglio la correlazione spaziale, i coefficienti DC di ogni blocco sono codificati
come la differenza dei blocchi DC precedente e successivo.

Il processo di decodifica altro non è che l'inverso di quello di codifica: il decoder entropico
decodifica la sequenza a “zig zag” dei coefficienti DCT quantizzati e, dopo averli de-quantizzati,
vengono ri-trasformati in blocchi da 8x8.
Le matrici di quantizzazione non sono standardizzate, bensì il JPEG suggerisce una matrice di
quantizzazione utilizzando i valori corrispondenti alle minime differenze percettive di ogni
coefficiente DCT.
Questa matrice di quantizzazione di base può essere utilizzata per generare matrici di
quantizzazione di qualità più bassa semplicemente moltiplicando la matrice di partenza con un certo
coefficiente di quantizzazione intero.
I processi di quantizzazione sono prevalentemente bassi per le basse frequenze
ed alti per le alte frequenze.
In questo modo, il noise di quantizzazione è concentrato nelle frequenze di percezione visiva
minore ed è molto importante in quanto sfrutta l'irrilevanza di segnale, ovvero evita di trasmettere
informazioni di immagine che non hanno importanza a livello percettivo.
Infine, la matrice di quantizzazione (se utilizzata) deve essere trasmessa.
Chiaramente, più la quantizzazione è marcata, più il rapporto di compressione aumenterà e più la
qualità dell'immagine finale ricostruita ne sarà affetta.

È facilmente possibile percepire come l'immagine di sinistra, processata con una forte
quantizzazione JPEG, al costo di avere una codifica maggiore (e quindi occupare meno spazio)
introduca anche dei vistosi artefatti da compressione quali ad esempio il blocking, il blur (sfocatura)
ed il banding (bande di colore nel cielo invece di un gradiente uniforme di sfumatura).
Come detto precedentemente, i blocchi vengono processati dal quantizzatore che effettua un
“taglio” di parte dell'informazione nella codifica lossy.
Ebbene, il quantizzatore rimuoverà per prime le alte frequenze poiché sono meno importanti dal
punto di vista percettivo rispetto alle basse frequenze.
È inoltre doveroso aggiungere che, per quanto riguarda il JPEG (ma tanti altri standard utilizzano lo
stesso approccio) al momento del processo di DCT, l'immagine viene considerata nelle sue due
componenti fondamentali, quali il “luma” ed il “chroma”.
Il luma è definito come la composizione dell'immagine in scala di grigi, mentre il chroma è la sua
componente di colore.

A sinistra è rappresentata l'immagine originale, mentre a destra sono rappresentate le sue


componenti di luma e chroma.
In altre parole, l'immagine e la sua componente di colore vengono separate, processate
separatamente mediante il processo sopraelencato relativo ai blocchi da 8x8 e poi ri-assemblate
per poter ricreare l'immagine finale.
L'occhio umano percepisce meglio il luma del chroma (cioè l'immagine rispetto al colore), dunque,
in fase di quantizzazione, verrà data più importanza al luma e minore al chroma; in altre parole,
verranno tagliate maggiormente le frequenze relative al chroma rispetto a quelle relative al luma.
Questo perché all'interno dell'occhio umano sono presenti due tipologie di cellule quali Coni e
Bastoncelli e ciò consente alla nostra tre diverse tipologie di visioni: fotopica, mesopica e scotopica.
Nella visione fotopica (molta luce), solo i coni (che sono in grado di percepire luma e chroma) sono
in funzione (immagine in alto).
Nella visione mesopica (media luce), i soli coni non sono sufficienti ad offrire una corretta visione
ed entrano in gioco i bastoncelli che, però, sono in grado di percepire solamente il luma, ma non il
chroma (immagine media).
Nella visione scotopica (scarsa luce), solo i bastoncelli sono attivi e la visione è principalmente in
bianco e nero con pochissima sensibilità alle variazioni di colore (immagine in basso).
In questo caso, abbiamo dunque una differenza della variazione di colore del fiore rappresentato
sopra durante la giornata, quindi abbiamo una variazione della sua percezione nel campo del
chroma, ma non in quello del luma che resta invariato.

2.2) Lo Standard JPEG 2000

Il JPEG 2000 venne creato attorno al 2000 con l'obiettivo di ottenere una miglior compressione a
parità di qualità rispetto allo standard precedente.
Ogni immagine può essere codificata per intero oppure divisa in “tile” ovvero aree rettangolari non
sovrapposte che sono compresse indipendentemente e, talvolta, una “tile” può corrispondere ad
un'intera immagine.
Per prima cosa, ogni tile (o l'intera immagine, a seconda dei casi) è trasformata utilizzando la
Trasformata Discreta di Wavelet bidimensionale.
Grazie a questo processo, le immagini, dalle loro due componenti (luma e chroma),
sono scomposte in differenti livelli di risoluzione.
Tali livelli sono effettuati su sotto bande popolate dai coefficienti della Trasformata di Wavelet che
descrivono le caratteristiche di frequenza delle aree locali di ogni componente dell'immagine.
È lecito ricordare che la Trasformata Discreta di Wavelet può essere irreversibile (metodo di
default) o reversibile.

Ad ogni modo, dopo il processo di trasformata, i coefficienti sono sottoposti ad una quantizzazione
scalare uniforme, sfruttando una zona morta prefissata attorno all'origine.
La dimensione del passo di quantizzazione è consentita per sotto-bande, ad ogni modo,
il JPEG 2000 non definisce alcun metodo particolare per il passo di quantizzazione,
quindi è possibile utilizzare svariati metodi a proprio piacimento.
Questo fatto può tornare molto comodo in quanto è possibile aggiustarlo in base all'importanza
visiva dei coefficienti di sotto-banda; in altre parole è possibile utilizzare un passo di quantizzazione
più grande per i coefficienti meno importanti dal puro punto di vista di qualità visiva
ed un passo più piccolo per quelli più importanti.
Dopo la quantizzazione, ogni sotto-banda della scomposizione di trasformata è divisa in un blocco
rettangolare non sovrapposto chiamato “blocco di codifica” e la codifica entropica è effettuata
indipendentemente su ognuno di essi, bitplane per bitplane.

I bitplane sono array binari rappresentanti un blocco di codifica dal suo bit più significativo
a quello meno significativo.
Ogni bitplane è codificato con una codifica adattiva binaria basata sul contesto in modo da ottenere
un bit-stream molto complesso per ogni blocco.
Ogni bit-stream viene poi organizzato in pacchetti.
Ogni pacchetto può essere interpretato come un incremento di qualità per un livello di risoluzione in
una locazione spaziale.
Questi pacchetti vengono poi raggruppati in strati dove ogni strato può essere interpretato come un
incremento di qualità per l'intera immagine a risoluzione completa.

I vantaggi del JPEG 2000 rispetto al JPEG si possono notare maggiormente a bitrate molto bassi
poiché il JPEG 2000 non soffre del blocking.
Questo perché, dato che il JPEG utilizza la DCT che calcola ogni blocco di pixel indipendentemente
(e può quindi esserci blocking), la Trasformata di Wavelet (per il procedimento visto sopra) analizza
l'intera immagine (o una tile).
Di seguito, sono riportati alcuni esempi di codifica JPEG contro il JPEG 2000 a bassi bitrate.
È possibile notare la qualità visiva sensibilmente maggiore in quest'ultimo standard.

Ad ogni modo, proprio per la differenza delle due trasformate utilizzate, il vantaggio del JPEG 2000
diventa pressoché nullo ad alti bitrate: per immagini di 0.25bpp il peso di quella in JPEG 2000 è del
53% minore, mentre per immagini a 1.00bpp è più piccolo solo del 18%.
È possibile dunque notare come, in immagini con un bitrate relativamente alto, la differenza
percettiva sia molto minore.
Non solo, la decodifica del JPEG 2000 comporta anche una maggiore complessità rispetto a quella
del JPEG.

2.3) Lo standard GIF

Analizzando i due standard precedenti è stato introdotto il termine “lossless” (privo di perdita)
senza però prestare particolare attenzione a questo metodo di codifica.
Analizzando lo standard GIF – basato su una codifica lossless – è possibile andare a vedere nel
dettaglio tale tipo di codifica ed analizzare i pregi ed i difetti comparandola ai due tipi di codifica
lossy (con perdita) introdotti con gli standard JPEG e JPEG 2000.
Prima di cominciare, però, è doveroso ricordare che lo standard GIF ha subito due aggiornamenti di
versione, ovvero il GIF87a ed il GIF89a (utilizzato per lo più per le animazioni) e la versione
utilizzata è ricavabile dai caratteri ASCII dei primi 6 byte del file codificato.
Seppur lo standard GIF utilizzi una codifica lossless basata su un algoritmo di compressione
lossless universale ideato da Lempel, Ziv e Welch e che prende il nome da tali (LZW), durante il
processo di conversione di un'immagine in GIF ci può essere una sostanziale perdita di qualità
e di informazioni.
Questo perché la codifica GIF associa ad ogni pixel un numero di bit che va da 1 ad 8 ed associa,
tramite questi, un massimo di 256 diversi possibili colori ed ogni pixel potrà assumere uno tra
questi 256 possibili colori.

– Algoritmo di Huffman e quello di Lempel Ziv Welch

Come è stato elencato sopra, lo standard di codifica GIF utilizza l'algoritmo LZW, tuttavia, è
necessario analizzare anche l'algoritmo di Huffman in quanto quello di LZW dipende da esso.
Supponiamo che la fonte in ingresso mandi una sequenza di simboli di un alfabeto.
Tale alfabeto può essere un testo oppure una sequenza di bit corrispondente ad un'immagine digitale
od anche un video.
Di base, un codice è mappato in simboli e parole di codice.
Il motivo per cui è mappato è che è preferibile adattare il messaggio in una forma che può essere
manipolata (processata), salvata e trasmessa tramite i canali di comunicazione e le parole di codice
fatte di bit (zero ed uno) sono un modo efficiente per farlo.
Ad esempio, se volessimo comunicare delle lettere dell'alfabeto quali A, B, C, D per indicare i
livelli di efficienza energetica di una determinata marca di frigoriferi, utilizzeremmo 1 per A, 01 per
B, 000 per C e 001 per D.
Se volessimo poi mandare una sequenza di lettere tipo DCAAABCB possiamo mandare un unico
messaggio che sarà 0010001110100001 e sarà il ricevitore a decodificarlo per poter ottenere tali
lettere.
Nel processo di decodifica, dunque, il decodificatore andrà a cercare le appropriate sotto-stringhe
contigue non sovrapposte del messaggio ricevuto nel codice condiviso e nella source.
Una proprietà molto utile che un codice dovrebbe possedere è che un simbolo corrispondente ad
una parola di codice ricevuta può essere decodificato appena la parola di codice corrispondente è
ricevuta; in tal caso si parla di codice istantaneo.
L'esempio che ho riportato prima è proprio un codice istantaneo.
Il motivo è che se il ricevitore ha già decodificato la sequenza e, successivamente,
riceve nuovamente 1, sa già che il simbolo corrispondente sarà per forza A.
Se riceve uno 0, allora aspetterà il bit successivo e, se questo è un 1, allora sa che il simbolo è B,
mentre se è un altro 0, sarà ancora incapace di sapere quale simbolo è ed aspetterà ancora una volta
quello successivo ed allora saprà per certo quale lettera sarà: 0 darà C mentre 1 darà D.
Per quanto riguarda invece i codici non istantanei, questi sono più difficili da decodificare.
Ad esempio, prendiamo la solita lista A, B, C, D ed assegniamo 0 ad A, 01 a B, 011 a C ed 111 a D.
In questo modo, abbiamo un codice non istantaneo e, se riceviamo una stringa del tipo 01111101,
non siamo in grado di decodificare il primo simbolo come A semplicemente ricevendo il primo 0.
Difatti, non possiamo essere sicuri che il primo simbolo sia A poiché potrebbe anche essere B.
Di conseguenza, si deve aspettare la fine della trasmissione della sequenza per cominciare a
decodificare ed, in questo caso, la sequenza decodificata è BDB.
Questo codice preso in esempio è unicamente decodificabile, ma non è sempre così con i codici non
istantanei, cosa che invece non accade nei codici istantanei che sono tutti unicamente decodificabili.
Un esempio di un codice non istantaneo non unicamente decodificabile può essere il seguente:
A con 0, B con 1, C con 01 e D con 11.
Con questo codice possono esistere diverse sequenze di bit che non mappano un unico simbolo;
ad esempio, 01 potrebbe essere AB oppure solo C.
Ad ogni modo, dato che la maggior parte delle codifiche lossless fanno utilizzo di codici istantanei,
mi limiterò ad analizzare quest'ultimi.
Un modo conveniente per visualizzare i codici è il metodo dell'albero di codice.
Nell'esempio, riporto l'albero di codice per la sequenza A con 10, B con 0, C con 110 e D con 111.

In generale, un albero di codice è un albero binario con tre simboli ai nodi e le cui estremità sono
0 o 1 a significare l'encoding.
Per trovare l'encoding di un simbolo, il ricevitore deve semplicemente percorrere il percorso che va
dall'inizio dell'albero fino alla lettera desiderata.
Ad esempio, partiremo dall'alto e ci sposteremo a sinistra, trovando B (0).
Oppure, partiremo dall'alto, scenderemo di una posizione e troveremo 1, poi ci sposteremo a sinistra
e troveremo 0, quindi 10 ovvero A e così via.
È necessario aggiungere un'altra definizione prima di andare a parlare dell'algoritmo di Huffman ed
è quella della lunghezza di codice aspettata.
Dati N simboli, con simboli i che si presentano con probabilità p con i, se abbiamo un codice il cui
simbolo i ha lunghezza l con i, nell'albero di codice (ovvero la parola di codice lunga l con i bit) la
lunghezza di codice aspettata sarà:
In generale, i codici con una piccola lunghezza di codice aspettata sono utili perché consentono
di comprimere i messaggi, consegnandoli senza alcuna perdita di informazione (lossless),
ma consumando comunque meno bit.
Diremo quindi che la lunghezza L debba essere più corta possibile, in quanto più è possibile
comprimere tali dati senza perdita, meglio è.
L'albero di codice corrispondente ci dà la mappatura ottimale tra i simboli e le parole di codice e,
solitamente, non è unico.
È stato dimostrato inoltre che la lunghezza di codice aspettata di ogni codice decodificabile non può
essere più piccola dell'entropia, H, della sottostante probabilità di distribuzione tra i simboli.
È stato inoltre dimostrata l'esistenza di codici che raggiungono l'entropia asintoticamente come la
lunghezza di codice dei messaggi si approssima all'infinito.
Inoltre, un codice ottimale deve avere una lunghezza di codice aspettata che concordi con l'entropia
per i lunghi messaggi.
Tenendo conto di tutto quello esplicato sopra, è ora possibile andare ad introdurre due metodi di
codifica: il primo metodo, quello di Huffman, è ottimale per codici istantanei quando le probabilità
dei vari simboli sono note, i simboli sono indipendenti ed identicamente distribuiti con tali
probabilità e la mappatura è ristretta ad un “simbolo per simbolo”.
Il secondo, l'algoritmo LZW, adotta l'attuale distribuzione di simboli nel messaggio,
non rifacendosi ad alcuna conoscenza della probabilità dei simboli.

– La Codifica di Huffman:

La codifica di Huffman effettua un encoding efficiente per una lista di simboli che devono essere
trasmessi quando sappiamo la probabilità di un dato messaggio.
Tornando ad analizzare l'albero di codici analizzato sopra, è possibile notare come i simboli più
probabili (ad esempio B) siano più vicini all'inizio dell'albero e quindi hanno una codifica più corta,
mentre quelli meno probabili (tipo C o D) sono più distanti ed hanno una codifica più lunga.
David Huffman utilizzò questa osservazione per realizzare un algoritmo di decodifica ad albero
per un codice di lunghezza variabile ottimale.
Quello che Huffman voleva fare era creare un albero di decodifica dal basso verso l'alto
che cominciasse con i simboli meno probabili.
In entrata all'algoritmo abbiamo dunque un set di simboli e le loro rispettive probabilità di
occorrenza.
In uscita, abbiamo un albero di codifica dal quale è possibile leggere la parola chiave
corrispondente ad ogni simbolo.

1) Ingresso: un set di S tuple. Ogni tupla consiste in un simbolo di messaggio e la sua


probabilità associata.
Esempio: S←{(0.333, A), (0.5, B), (0.083,C), (0.083, D)}
2) Vengono poi rimosse da S le due tuple con la probabilità più bassa. Poi, i due simboli delle
tuple rimosse vengono combinati per formare una nuova tupla (che rappresenta un nodo
interno dell'albero di codici). Viene poi computata la probabilità di questa nuova tupla
aggiungendo le due probabilità dalle tuple.
Questa nuova tupla viene in seguito aggiunta ad S.
Per far chiarezza, diciamo che se S ha N tuple all'inizio, ora ne ha N – 1 poiché due tuple
erano state rimosse e ne è stata aggiunta nuovamente una sola).
Esempio: S←{(0.333, A), (0.5, B), (0.167,C ∧ D)}
3) Viene poi ripetuta la fase due finché S contiene una sola tupla.
Esempio: S←{(0.5, B), (0.5, A ∧ (C ∧ D))}
S←{(1.0, B ∧ (A ∧ (C ∧ D)))}

Il risultato è dunque un albero di codice che rappresenta un codice di lunghezza variabile per i dati
simboli e probabilità.
La codifica di Huffman dà risultati migliori quando alcuni simboli sono sostanzialmente più
probabili di altri.
Se tutti i simboli sono equiprobabili, allora tutte le parole di codice saranno approssimativamente
della stessa lunghezza.
Per quanto concerne le proprietà della codifica di Huffman, mi limiterò ad elencarne alcune,
senza però dimostrarle formalmente.

Non unicità: Banalmente, dato che 0/1 parti di ogni coppia di rami in un albero di codice possono
essere invertiti, ci sono diversi encoding che hanno la stessa lunghezza aspettata. Difatti, potrebbero
esserci diversi codici ottimali per un dato set di probabilità di simboli e, a seconda di quanti legami
sono spezzati, la codifica di Huffman può produrre diversi alberi di codice non isomorfi, ovvero
alberi di codice che sembrano strutturalmente diversi.
Ad esempio, se prendiamo sei simboli le cui probabilità sono ¼, ¼, 1/8, 1/8, 1/8, otterremo i
seguenti alberi di codice (entrambi validi):

Ottimizzazione: La codifica di Huffman è ottimizzata nel senso che non ci sono codici con una
lunghezza aspettata minore quando ristretti a dei codici istantanei ed i messaggi occorrono in una
forma ideale in una probabilità di distribuzione conosciuta.

In ogni albero di codice ottimale per un codice senza prefisso, ogni nodo può avere due figli o non
averne.

Per dimostrarlo, supponiamo che un albero di codice ottimale abbia un nodo con un figlio.
Se prendiamo quel nodo e lo muoviamo in su di un livello al suo padre, avremo ridotto la lunghezza
di codice aspettata, lasciando il codice ancora decodificabile.
In questo caso, allora, significa che l'albero di codice di partenza non era un albero di codice
ottimale.

Nell'albero di codice di una codifica di Huffman, nessun nodo ha esattamente un figlio.

Anche questa proposizione è ovvia, in quanto, come detto sopra nei 3 punti della codifica di
Huffman, abbiamo sempre combinato i due nodi con la probabilità più bassa in un singolo nodo,
il che significa che nell'albero di codifica, ogni nodo interno deriva da due nodi combinati assieme.

Esiste un codice ottimale in cui i due simboli meno probabili hanno la lunghezza più lunga e sono
fratelli, ovvero le loro parole di codice differiscono esattamente di un solo bit, l'ultimo.

Supponiamo che z sia il simbolo meno probabile.


Se non è alla massima profondità nell'albero di codice ottimale, allora qualche altro simbolo
(chiamiamolo s) deve essere alla massima profondità.
Tuttavia, dato che p con z è minore di p con s, se scambiassimo z ed s nell'albero di codice,
finiremmo con un codice con una lunghezza aspettata più piccola.
Dunque, z deve avere una parola di codice lunga almeno quanto ogni altra parola di codice.
Ora, il simbolo z deve avere un fratello nell'albero di codice ottimale (per quanto detto sopra)
e lo chiameremo x. Diciamo inoltre che y è il simbolo con la seconda probabilità più bassa,
ovvero px ≥ py ≥ pz.
Se px = py, allora la proposizione sopraelencata è dimostrata.
Se cambiamo x con y nell'albero di codice, avremo y fratello di z.
La lunghezza di codice aspettata di quest'albero di codice non è più grande dell'albero di codice
ottimale prima del cambio perché p con x è più grande di p con y,
il che prova la proposizione sopraelencata.

La codifica di Huffman produce un albero di codice la cui lunghezza aspettata è ottimale quando
ristretto ad una codifica “simbolo per simbolo” con simboli in forma ottimale e con una
probabilità di distribuzione conosciuta.

Facciamo sì che i simboli siano x1, x2, . . . , xn−1, xn e facciamo sì che le rispettive probabilità di
occorrenza siano p1 ≥ p2 ≥ . . . ≥ pn−1 ≥ pn.
Da quanto detto sopra, esiste un albero di codice ottimale in cui xn−1 e xn hanno la lunghezza
maggiore e sono fratelli.

Ipotesi induttiva: presupponiamo che la codifica di Huffman produca un albero di codice ottimale
con un input di n – 1 simboli con associate probabilità di occorrenza.
Facciamo sì che Hn sia il costo dell'albero di codice generato dalla codifica di Huffman
negli n simboli x1, x2, . . . , xn.
Poi, Hn = Hn−1 + pn−1 + pn, dove Hn−1 è il costo aspettato dell'albero di codice generato dalla
codifica di Huffman su n – 1 simboli in ingresso x1, x2, . . . xn−2, xn−1,n
con delle probabilità p1, p2, . . . , pn−2, (pn−1 + pn).
Dall'ipotesi induttiva: Hn−1 = Ln−1, il costo aspettato per l'albero di codice ottimale su n – 1
simboli.
Inoltre, per quanto detto sopra, esiste un albero di codice ottimale su n simboli
per cui Ln = Ln−1 + (pn−1 + pn).

Dunque, esiste un albero di codice ottimale il cui costo aspettato, Ln, è uguale al costo aspettato, Hn,
della codifica di Huffman su n simboli.

Codifica di Huffman con simboli raggruppati: Supponiamo che la codifica di Huffman per dei dati
simboli produca un codice con una lunghezza aspettata di un certo tot.
La domanda che è lecito porsi è: possiamo utilizzare la codifica di Huffman per avvicinarci
all'entropia?
Un approccio potrebbe essere quello di raggruppare i simboli in dei “meta-simboli” più grandi
ed encodare quest'ultimi.
Consideriamo allora di encodare coppie di simboli, triple di simboli, quadruple di simboli e così via.
È possibile quindi avvicinarsi all'entropia aumentando il numero di simboli encodati per volta,
ma al costo di aumentare anche la complessità di codifica e decodifica.
Tale approccio ha comunque due problemi di base: il primo è che bisogna sapere la probabilità
di ogni simbolo, il secondo è che bisogna presuppone che la probabilità di ogni simbolo sia
indipendente ed equamente distribuita.
Ad ogni modo, nella realtà delle cose, la probabilità dei simboli cambia messaggio per messaggio o,
alcune volte, addirittura nel mezzo di uno stesso messaggio.
Dunque, sarebbe opportuno creare un encoding a lunghezza variabile adattivo
che tiene in considerazione il contenuto di ogni messaggio, ma la cosa bella è che tale encoding
esiste già ed è proprio l'algoritmo LZW che analizzerò di seguito!

Per poter esplicare meglio il problema, andiamo ad analizzare il problema di rappresentare


digitalmente e trasmettere i caratteri di un libro (per esempio).
L'approccio più semplice sarebbe quello di analizzare tale libro e di fare una stima della probabilità
della ricorrenza di diverse lettere dell'alfabeto, dopodiché trattare ogni lettera come simbolo ed
applicare la codifica di Huffman per comprimere il tutto.
Questo metodo è assolutamente legittimo e funzionante,
tuttavia permette di avere solo un leggero guadagno in termini di compressione.
Questo perché la probabilità con cui una lettera compare non è sempre la stessa.
Ad esempio, possiamo fare una stima dell'utilizzo delle vocali e dare loro più importanza
per poi andare a fare un elenco della ricorrenza delle consonanti, ma può capitare che,
in una determinata frase, alcuni consonanti catalogate come “meno importanti”
possano comparire più volte.
Inoltre, tornando all'inizio del nostro approccio, abbiamo detto di aver voluto scegliere come
“simboli” le lettere, tuttavia, a seconda del contesto analizzato,
avremmo addirittura potuto scegliere le parole.
Dunque, un metodo che si adatti al materiale che deve essere compresso
può portare vantaggi significativi.
Un approccio di codifica adattiva è quello di utilizzare la doppia passata: nel primo passo si effettua
il conteggio del numero di volte in cui ogni simbolo compare, dopodiché viene utilizzato
tale conteggio per sviluppare una codifica di Huffman adatta a quel tipo di file.
Ovviamente, è possibile analizzare anche coppie di simboli o triple di simboli od anche quadruple
di simboli (e così via) a seconda del livello di raggruppamento scelto.
Per quanto concerne la seconda passata, viene effettuato l'encoding vero e proprio utilizzando
la codifica di Huffman personalizzata.
Ad ogni modo, anche così facendo non si raggiunge ancora la massima efficienza.
Il fatto è che, a prescindere dal livello di raggruppamento scelto, non ci sarà mai una codifica
ottimale per i gruppi di grandezza diversa (siano questi più grandi o più piccoli).
Inoltre, se le probabilità di un simbolo cambia radicalmente in un certo punto del file,
una codifica di Huffman fatta in questo modo risulterà comunque non essere ottimale.
Un altro approccio di codifica adattiva è proprio quello utilizzato dalla LZW.
Appena il messaggio da codificare è processato, l'algoritmo di codifica LZW crea una tabella di
stringhe (arbitrariamente lunga) che mappa le sequenze di simboli in un index di N-bit.
La tabella di stringhe ha 2^N voci in entrata ed il codice trasmesso può essere utilizzato dal decoder
come index della tabella di stringhe per poter ricostruire la sequenza di simboli originale.
L'algoritmo è sviluppato in modo che la tabella di stringhe possa essere ricostruita dal decoder in
base alle informazioni nello stream encodato; in altre parole, la tabella di stringhe non è mai
trasmessa ed è proprio questo il principale vantaggio della codifica LZW.
Quando si encoda un byte stream (ovvero più stringhe di 8bit ciascuna), le prime 2^8 (256) voci in
entrata alla tabella di stringhe (numerate da 0 a 255) sono inizializzate a contenere
tutte le possibili sequenze ad un byte.
Le altre voci in entrata saranno compilate appena il byte stream sarà processato.
Il procedimento di codifica è semplice e si divide in varie fasi.
Per prima cosa, vengono accumulati byte di messaggio finché le sequenze accumulate compaiono in
qualche voce in ingresso della tabella di stringhe.
Ad un certo punto, l'appending tra il byte successivo (chiamiamolo b) con la sequenza accumulata
(chiamiamola S) creerà una sequenza S+b che non è più nella tabella di stringhe.
L'encoder poi procederà trasmettendo il codice di N-bit per la sequenza S, aggiungerà una nuova
voce in ingresso nella tabella di stringhe per S+b (se la tabella è piena al momento dell'aggiunta
della nuova voce in ingresso, prima di aggiungerla) ed infine resetta S
per poter contenere solo il byte b.
Questo processo viene ripetuto finché non vengono consumati tutti i byte;
a quel punto l'encoder esegue la trasmissione finale del codice di N-bit per la sequenza S corrente.
Notiamo dunque come, per ogni trasmissione fatta dall'encoder,
questi crea una nuova voce di ingresso nella tabella di stringhe.
Il decoder, dunque, è in grado di capire quali siano le nuove voci in ingresso
non appena riceve il rispettivo codice di N-bit.
Con una tavola di stringhe duplicata costruita dal decoder man mano che l'algoritmo procede,
è possibile risalire al messaggio d'origine: basta usare il codice di N-bit ricevuto come index nella
tavola di stringhe del decoder.

2.4) Lo standard PNG

Come ultimo standard della codifica delle immagini, procederò ad analizzare nel dettaglio il PNG
in quanto uno degli standard più diffusi per la codifica delle immagini fisse in modo lossless.
Lo standard PNG venne ideato proprio come sostituto del GIF e ne conserva alcune funzionalità
quali le immagini indexate con un massimo di 256 colori, la possibilità di leggere e scrivere file in
maniera seriale, la possibilità di elaborare le immagini in maniera immediata appena ricevute (come
quando si clicca un link) per poi procedere ad un successivo incremento della qualità, la possibilità
di marcare parti di immagini come trasparenti, la possibilità di salvare all'interno del file di
immagine stesso dei commenti ed ovviamente, come già detto, il fatto di essere lossless.
Oltre a queste precedenti possibilità, il PNG introduce anche alcune importanti innovazioni quali
immagini con chroma fino a 48 bit per pixel, mentre le immagini con solo luma sono possibili fino
a 16 bit per pixel; un alpha channel completo per una gestione migliore della trasparenza,
informazioni sulla gamma dell'immagine (che supporta la corretta riproduzione dell'immagine con
luminosità e contrasto riprodotti correttamente a prescindere dalla macchina utilizzata per
riprodurre l'immagine), un affidabile autocontrollo per individuare file corrotti
ed una rappresentazione iniziale più veloce nei display progressivi.

– Rappresentazione dei dati

Tutti gli interi che richiedono più di un byte devono essere ordinati con quelli più significativi prima
e quelli meno significativi dopo in discendente ordine di importanza.
Il bit più alto (di valore 128) di un byte è numerato bit 7, mentre il bit più basso (di valore 1)
è numerato bit 0.
I valori sono unsigned a meno che non sia esplicitato diversamente;
in caso di valori signed, questi sono rappresentati in notazione complemento a due.
In caso di valori unsigned, interi da 4 byte sono limitati al range da 0 a 2^31 -1 per compatibilità,
mentre per quelli signed, gli interi da 4 byte sono limitati al range da -(2^31 – 1) a 2^31 – 1 per
compatibilità.

– Valori dei Colori

Le immagini possono essere rappresentate sia con solo il luma,


sia con il chroma in RGB (red, green, blue).
In caso di immagini a colori, questi possono essere rappresentati con informazioni di colore
calibrate (se il cHRM è presente) o non calibrate (se il cHRM è assente).
Il range dei valori di colore va da zero (che rappresenta il nero) alla massima intensità al massimo
valore per la stessa profondità (considerando il valore massimo di una data profondità come
2^profondità -1 e non 2^profondità).
I valori dei dati non sono necessariamente proporzionali all'intensità luminosa;
il gAMA specifica la relazione tra i valori dei dati e l'intensità del display in output.
I dati in ingresso con una precisione non direttamente supportata dal PNG vengono scalati
alla massima profondità di bit più vicina supportata.
Il processo di scalatura è reversibile e non implica perdita di dati,
inoltre riduce il numero di casi che i decoder devono affrontare.

– Layout delle immagini

Concettualmente, un'immagine PNG è un array rettangolare di pixel, con i pixel che appaiono da
sinistra verso destra ad ogni scansione di linea e tali scansioni avvengono dall'alto verso il basso.
La dimensione di ogni pixel è determinata dalla profondità di bit (bit depth).
Ci sono tre tipi di pixel supportati:

1) Pixel a Colori Indexati: ovvero pixel rappresentati da un singolo dato che è nell'index in una
tavolozza fornita. La profondità di bit dell'immagine determina il numero massimo di
tavolozze in entrata, ma non la precisione di colore delle stesse.

2) Pixel in bianco e nero: ovvero rappresentati da un singolo dato in un livello in bianco e nero,
dove zero è nero ed il massimo valore possibile per la profondità di bit è bianco.

3) Pixel TrueColor: ovvero rappresentati da tre dati quali rosso (zero equivale a nero ed il
massimo al rosso), verde (zero equivale a nero ed il massimo al verde) e blu (zero equivale a
nero ed il massimo al blu). La profondità di bit specifica la grandezza di ogni dato,
non la grandezza totale dei pixel.

A seconda della necessità, i pixel in bianco e nero e quelli in TrueColor possono includere anche
dati alpha dei quali parlerò più approfonditamente in seguito.
I pixel sono sempre raggruppati in scanline senza alcun spreco di bit tra i pixel.
I pixel più piccoli di un byte sono salvati in byte con il pixel più a sinistra nei bit di ordine superiore
di un byte, quelli più a destra nei bit di ordine minore.
Le profondità di bit permesse ed i tipi di pixel sono ristretti,
in modo da rendere il salvataggio semplice ed efficiente.
Quando i pixel hanno meno di 8 bit e la larghezza delle linee di scansione non è divisibile per il
numero di pixel per byte, i bit di ordine minore nell'ultimo byte di ogni linea di scansione vengono
buttati ed il loro contenuto non è specificato.
Un byte “filter-type” aggiuntivo è aggiunto all'inizio di ogni linea di scansione e questo non viene
considerato parte dei dati dell'immagine, ma è incluso nello stream di dati inviato in fase di
compressione.

– Il canale alpha

Il canale alpha rappresenta le informazioni di trasparenza per pixel e può essere incluso sia nella
modalità in bianco e nero, sia in quella true color, come già detto sopra.
Il valore zero dell'alpha rappresenta una trasparenza completa, mentre un valore di 2^bitdepth − 1
rappresenta un pixel completamente opaco.
Valori intermedi, dunque, indicano pixel parzialmente trasparenti che possono essere combinati con
un'immagine di sfondo per comporre poi l'immagine finale.
Il canale alpha può essere incluso con immagini che hanno sia 8 che 16 bit per dato,
ma non con immagini che ne hanno meno di 8.
I dati del canale alpha sono rappresentati con la stessa profondità di bit utilizzata per i dati
delle immagini ed i dati del canale alpha per ogni pixel sono salvati immediatamente dopo i dati
dei pixel in bianco e nero o in RGB.
I valori di colore per ogni pixel non sono intaccati dal valore alpha assegnato allo stesso
e questa regola viene chiamata “non associatività”.
Ad ogni modo, il controllo della trasparenza è comunque possibile anche senza un canale alpha
completo: in un'immagine a colori indexati, il valore alpha può essere definito per ogni tavolozza in
entrata, mentre per le immagini in bianco e nero e per quelle in truecolor, il valore di un singolo
pixel può essere identificato come “trasparente”.
Tutto questo è gestito dal canale alpha o dai tRNS ausiliari, tuttavia, se nessuno dei due è presente,
i pixel vengono trattati come completamente opachi.

– Filtraggio

Lo standard PNG consente di filtrare l'immagine prima di comprimerla in modo da aumentarne la


compressibilità senza però perdere informazioni (visto che, appunto, ripeto, il PNG è lossless).
Lo standard PNG ha definito vari e diversi algoritmi per il filtraggio, inclusa la modalità “none”
che indica “nessuno” e quindi non filtra l'immagine.
L'algoritmo di filtraggio è specificato per ogni linea di scansione da un byte filter-type che precede
la linea di scansione filtrata nel datastream pre-compresso.
L'encoder può passare da un filtro ad un altro ed il metodo secondo il quale vengono scelti
è lasciato all'encoder stesso.

– Ordinamento dei dati interlacciati

Un'immagine salvata con lo standard PNG può essere salvata sia progressiva che interlacciata ed i
decoder sono in grado di leggere quest'ultima in ogni occasione,
indipendentemente dalla tipologia del display di riferimento.
Con il metodo di interlacciamento di tipo 0, i pixel sono salvati in sequenza da sinistra verso destra
e le linee di scansione sono in sequenza dall'alto verso il basso.
Con il metodo di interlacciamento di tipo 1, conosciuto come metodo di Adam M. Costello (nome
dell'autore), si hanno sette diverse passi sull'immagine: ogni passo trasmette un subset dei pixel
nell'immagine.
Il passo in cui ogni pixel è trasmesso viene definito replicando il seguente pattern 8 per 8,
cominciando da in alto a sinistra.
In ogni passo, i pixel selezionati sono trasmessi da sinistra verso destra in una linea di scansione
e le scansioni sono selezionate sequenzialmente dall'alto verso il basso.
Ad esempio, il secondo passo contiene i pixel 4, 12, 20 e così via delle linee di scansione 0, 8, 16
(contando da 0,0 in alto a sinistra); l'ultimo passo contiene invece 1, 3, 5 ecc.
I dati di ogni passo sono disposti come se fossero un'immagine completa delle dimensioni
appropriate; ad esempio, se un'immagine completa è di 16 per 16 pixel, allora il terzo passo conterrà
due linee di scansione, ognuna contenente quattro pixel.
Quando i pixel hanno meno di 8 bit, ogni linea di scansione è portata a raggiungere un intero
numero di byte.
Il filtraggio è fatto sull'immagine ridotta nel solito modo e viene trasmesso un byte filter-type
ad ogni linea di scansione.
Da notare, comunque, che l'ordine di trasmissione è definito in modo che tutte le linee di scansione
trasmesse in un passo abbiano lo stesso numero di pixel,
necessario per il corretto utilizzo di alcuni filtri.
Se però un'immagine contiene meno di cinque righe o meno di cinque colonne,
alcuni passi saranno completamente vuoti.
Gli encoder ed i decoder devono essere in grado di gestire anche questa particolare occasione e,
nello specifico, i byte filter-type sono associati solo con le linee di scansione non vuote, per cui,
in un passo vuoto, non ci sarà alcun byte filter-type.

– Correzione della Gamma

Le immagini codificate secondo lo standard PNG possono specificare, mediante il gAMA,


le informazioni relative alla rappresentazione in output.
I programmi per la riproduzione sono fortemente incoraggiati ad utilizzare queste informazioni in
modo da consentire una corretta riproduzione all'utente che sta guardando l'immagine, tuttavia,
la correzione di gamma non è applicata al canale alpha.
Per applicazioni di alto livello, l'esatta chromaticità dei dati RGB può essere specificata tramite il
cHRM, consentendo una riproduzione più accurata rispetto a quella offerta dalla sola correzione di
gamma normale.

– Stringhe di testo

Un file PNG è in grado di salvare porzioni di testo associate all'immagine, quali, ad esempio,
la descrizione delle immagini o informazioni relative al copyright.
Il set di caratteri consigliato è l'ISO/IEC 8859-1 (Latin-1) e, in caso le informazioni vengano scritte
in un set di caratteri diverso, c'è il rischio che i diversi decoder (nelle diverse piattaforme)
le interpretino in vario modo e potrebbero non essere in grado di riprodurle.

– Firma
Lo standard di codifica PNG include una firma che viene sempre riportata dai primi otto byte di
ogni file di immagine quali: 137 80 78 71 13 10 26 10 ed indica che il file è un'immagine
PNG e consiste in una serie di dati che cominciano con un dato IHDR e finiscono con un dato
IEND.

– Layout dei dati

Ogni dato consiste in quattro parti quali:

1) lunghezza: in intero di 4 byte unsigned che indica il numero di byte nel campo dati del dato.
La lunghezza conta solo il campo dati e non se stessa, il dato stesso per intero od il CRC e
“zero” è considerato un valore accettabile. Ad ogni modo, anche se molti decoder trattano la
lunghezza come unsigned, il suo valore non deve eccedere 2^31 − 1 byte.

2) Tipo di dati: è un codice di 4 byte. Per convenienza nella descrizione e nell'esaminazione dei
file PNG, i tipi di codice sono ristretti per consentire maiuscole e minuscole in lettere ASCII
(A-Z, a-z, oppure 65-90, 97-122 decimali). Ad ogni modo, encoder e decoder devono
trattare i codici come valori binari fissati e non come stringhe di caratteri.

3) Dati del tipo di dato: sono byte riferiti al tipo di dato, se ci sono. Nel caso non ci siano,
questo campo può tranquillamente assumere lunghezza zero.

4) CRC: il Cyclic Redunancy Check (Controllo di Ridondanza Ciclico) è fatto da 4 byte ed è


calcolato nei byte precedenti, incluso il codice del tipo di dati ed i dati del tipo di dato,
ma senza includere il campo della lunghezza ed è sempre presente, anche per i dati vuoti.

– Convenzione di nomenclatura dei dati

I dati del tipo "dati" sono assegnati in modo che il decoder possa determinare alcune proprietà di
tali dati anche senza riconoscere il tipo.
Queste regole sono state introdotte per questione di sicurezza e flessibilità del formato PNG,
consentendo ai decoder di decidere il da farsi quando incontrano un dato a loro sconosciuto;
ad ogni modo, le regole di nomenclatura di solito non sono contemplate quando il decoder
riconosce il tipo di dato.
Per trasmettere le proprietà dei dati, sono utilizzati quattro bit del codice del tipo,
ovvero 5 bit (di valore 32) di ogni byte.
Questa scelta significa che un umano è in grado di leggere le proprietà assegnate a seconda del caso
in cui ogni lettera del codice del tipo sia maiuscola (il quinto bit è 0) o minuscola (il quinto bit è 1).
Ad ogni modo, i decoder dovrebbero testare le proprietà di un dato sconosciuto testando
numericamente i bit specificati; testare se un carattere è maiuscolo o minuscolo è del tutto
inefficiente e persino incorretto in alcuni casi.
È del tutto insignificante sapere che i bit di proprietà sono parte integrante del nome dei dati e che
sono sistemati per ogni tipo di dato.
Dunque, BLOB e bLOb sarebbero tipi di dato non relazionati e non lo stesso dato
con proprietà differenti.
I decoder devono riconoscere i codici del tipo di dato eseguendo semplicemente un confronto a 4
byte.

Per quanto riguarda la semantica dei bit di proprietà, si dividono in:


1) Bit ausiliari: cinque bit del primo byte.
0 (maiuscolo) ovvero critico, 1 (minuscolo) ovvero ausiliario.
I dati che non sono strettamente necessari a riprodurre significativamente il contenuto del
file, sono considerati dati “ausiliari”. Un decoder che incontra un dato sconosciuto nel quale
il bit ausiliario è 1, può tranquillamente ignorarlo e procedere alla riproduzione
dell'immagine. Un esempio di dato critico è l'header (IHDR).

2) Bit privati: cinque bit del secondo byte.


0 (maiuscolo) ovvero pubblico, 1 (minuscolo) ovvero privato.
Un dato pubblico è parte delle specifiche PNG oppure è registrato nella lista dei tipi di dato
pubblici speciali. Le applicazioni possono anche definire dati privati (non registrati) per i
propri scopi. I nomi dei dati privati devono avere la seconda lettera minuscola, mentre a
quelli pubblici saranno sempre assegnati nomi con la seconda lettera maiuscola. Da notare
che i decoder non hanno bisogno di testare i bit di proprietà dei dati privati, visto che non
hanno un significato funzionale; è una semplice convenzione assicurarsi che i nomi dei dati
pubblici e privati siano corretti.

3) Bit di riserva: cinque bit del terzo byte.


0 (maiuscolo) in conformità con la corrente versione PNG.
I bit di riserva possono essere utilizzati nel caso in cui la terza lettera del nome del dato sia
riservata per una possibile espansione futura e tutti i nomi devono avere una terza lettera
maiuscola.

4) Bit sicuri da copiare: cinque bit del quarto byte


0 (maiuscolo) ovvero non sicuro da copiare, 1 (minuscolo) ovvero sicuro da copiare.
Questo bit di proprietà non è importante al puro scopo della decodifica, ma è necessario per
gli editor dei PNG (cioè programmi che modificano i PNG) in quanto definisce la corretta
gestione dei dati non riconosciuti in un file che è stato modificato.
Se è “sicuro da copiare” (1), il dato potrebbe essere copiato nel file PNG modificato sia che
il software ne riconosca il tipo o meno.
Se è “insicuro da copiare” (0), significa che il dato è dipendente dai dati dell'immagine. Se il
programma ha fatto qualche cambiamento ad alcuni dati critici, allora i dati “insicuri da
copiare” non devono essere copiati nel PNG di output.
L'editor dei PNG è sempre autorizzato a copiare tutti i dati non riconosciuti se ha solamente
aggiunto, rimosso, modificato o riordinato i dati ausiliari.
Se invece l'editor non è in grado di riconoscere un dato critico, dovrebbe riportare un errore
ed interrompere la modifica del file PNG.

– L'algoritmo CRC

I dati CRC sono calcolati utilizzando un metodo CRC standard ed il polinomiale utilizzato è:
x^32 + x^26 +x^23 +x^22 +x^16 +x^12 +x^11 +x^10 + x^8 +x^7 +x^5 + x^4 + x^2
+x+1
Il registro CRC a 32bit è inizializzato a tutti 1 e poi ogni dato da ogni byte viene processato
dall'ultimo bit significativo (1) a quello più significativo (128).
Quando tutti i dati sono processati, il registro CRC è invertito (viene preso il suo stesso
complemento) e tale valore viene poi trasmesso.
Per poterlo separare in byte ed ordinare, l'ultimo bit significativo del CRC a 32bit è definito per
essere il coefficiente dell' x^31esima termine.
– Header dell'immagine IHDR

Parlando della semantica dei bit di proprietà (in particolare dei bit ausiliari critici) ho utilizzato come
esempio l'header senza però specificare cosa fosse nel dettaglio.
L'IHDR deve apparire per primo e contiene 4 byte per la larghezza, 4 byte per l'altezza, 1 byte per la
profondità di bit, 1 byte per il tipo di colore, 1 byte per il metodo di compressione, 1 byte per il metodo di
filtraggio ed 1 byte per il metodo di interlacciamento.
Larghezza ed altezza indicano le dimensioni dell'immagine in pixel e sono date da interi di 4 byte; zero viene
considerato un valore non valido ed il massimo è di 2^31 − 1 in modo da evitare problemi con le
lingue che hanno difficoltà a gestire i valori di 4 byte unsigned.
La profondità di bit è data da un intero di un byte ed indica il numero dei bit per index di tavolozza
(e non per pixel) e può assumere i valori 1, 2, 4, 8 e 16, anche se non tutti sono consentiti per tutti i
tipi di colore.
Il tipo di colore è dato da un intero di 1 byte e descrive l'interpretazione del dato dell'immagine.
I codici del tipo di colore rappresentano somme dei seguenti valori: 1 (tavolozza utilizzata), 2
(colore utilizzato), 4 (canale alpha utilizzato) e può assumere valori 0, 2, 3, 4 e 6.
Le restrizioni della profondità di colore per ogni tipo di colore sono imposte per semplificare
l'implementazione e per proibire combinazioni che non sono ben comprimibili.
I decoder devono supportare tutte le combinazioni valide di profondità di bit e tipo di colore ovvero:
tipo di colore 0, profondità di bit consentite (1, 2, 4, 8, 16) – ogni pixel è in bianco e nero;
tipo di colore 2, profondità di bit consentite (8, 16) – ogni pixel è una tripla RGB;
tipo di colore 3, profondità di bit consentite (1, 2, 4, 8) – ogni pixel è un indice della tavolozza e
compaiono i dati PLTE;
tipo di colore 4, profondità di bit consentite (8, 16) – ogni pixel è in bianco e nero, seguito dal
canale alpha;
tipo di colore 6, profondità di bit consentite (8, 16) – ogni pixel è una tripla RGB, seguito dal canale
alpha.

I dati di profondità sono gli stessi di quelli della profondità di bit, eccetto nel caso del tipo di colore
3, in cui i dati della profondità sono sempre 8 bit.
Il metodo di compressione è un intero di un byte che indica il metodo utilizzato per comprimere i
dati dell'immagine.
Attualmente, solo il metodo di compressione 0 è definito.
Tutte le immagini compresse con lo standard PNG devono seguire questo schema.
Il campo del metodo di compressione è fornito per cambi futuri dello stesso standard ed i decoder
devono controllare questo byte e riportare un errore se ha un codice non riconosciuto.
Proseguendo al campo successivo, il metodo di filtraggio è dato da un intero di 1 byte che indica il
metodo di pre-processing applicato al dato dell'immagine prima della compressione.
Attualmente, solo il metodo 0 (filtraggio adattivo con cinque tipi di filtri base) è definito.
Per quanto riguarda il campo del metodo di compressione, i decoder devono controllare questo byte
e riportare un errore se ha un codice non riconosciuto.
Il metodo di interlacciamento, infine, è indicato da un intero di 1 byte che riferisce l'ordine dei dati
dell'immagine; attualmente sono definiti due valori: 0 (non interlacciato) oppure 1 (interlacciamento
Adam7).
Ad ogni modo, parlerò dell'ordine dei dati interlacciati più avanti.
– Tavolozze PLTE

I dati PLTE contengono da 1 a 256 tavolozze in entrata, ognuna delle quali ha una serie di tre byte
RGB: Red (1 byte; 0 equivale a nero, 255 a rosso), Green (1 byte; 0 equivale a nero, 255 a verde),
Blue (1 byte; 0 equivale a nero, 255 a blu), come già detto prima.
Il numero di valori in entrata è determinato dalla lunghezza dei dati e questa risulta in errore se non
è divisibile per 3.
Questo tipo di dato deve comparire nel tipo di colore 3 e può apparire per i tipi 2 e 6, ma non deve
comparire per i tipi 0 e 4.
Se questo dato compare, deve precedere il primo dato IDAT e non può esserci più di un dato PLTE.
Per il tipo di colore 3 (colori indexati), è richiesto il PLTE.
Il primo valore in entrata nel PLTE è riferito dal valore del pixel 0, il secondo dal valore del pixel 1
e così via.
Il numero di tavolozze in entrata non deve eccedere il range rappresentabile dalla profondità di bit
dell'immagine, ma è possibile averne meno.
Per i tipi di colore 2 (truecolor) e 6 (truecolor con il canale alpha), i dati PLTE sono opzionali.
Se presenti, dichiarano un set di colori suggerito da 1 a 256 col quale l'immagine truecolor può
essere quantizzata se l'utente non è in grado di riprodurre l'immagine truecolor direttamente.
Se non sono presenti né il PLTE, né l'sPLT, l'utente dovrà scegliere i colori da solo,
ma è preferibile che tale scelta venga fatta dall'encoder.
È doveroso ricordare che la tavolozza utilizza 8 bit (1 byte) a prescindere dalla profondità di bit
dell'immagine.

– Dati dell'immagine IDAT

I dati IDAT vengono creati a partire dalle linee di scansione dell'immagine rappresentate come
descritto precedentemente e la dimensione finale di questi dati è determinata dai campi dell'IHDR.
Dopodiché, i dati dell'immagine vengono filtrati secondo il metodo di filtraggio specificato sempre
dall'IHDR.
Infine, i dati dell'immagine sottoposta a filtraggio vengono compressi utilizzando il metodo di
compressione specificato, ancora, dall'IHDR.
I dati IDAT contengono lo stream di dati di output e l'algoritmo di compressione.
Per leggere i dati dell'immagine, il processo è l'inverso.
Possono esserci più dati IDAT e, in quel caso, appaiono consecutivamente e lo stream di dati
compresso sarà la concatenazione di tutti i dati IDAT.
Gli encoder possono dividere lo stream di dati compresso in dati IDAT a piacimento: sono
consentiti più dati IDAT in modo che gli encoder possano lavorare in una certa quantità di memoria
e, generalmente, la dimensione dei dati corrisponde al buffer size dell'encoder.
È doveroso ricordare che i bordi dei dati IDAT non hanno importanza a livello semantico e possono
collocarsi in qualsiasi punto dello steam di dati compresso.
Un file PNG nel quale ogni dato IDAT contiene solo un byte di dati è valido, seppur rappresenti un
incredibile spreco di spazio; allo stesso modo, anche i dati IDAT di lunghezza zero sono validi,
seppur rappresentino uno spreco ancora più grande!

– Il dato IEND

L'IEND deve apparire per ultimo in quanto indica la fine dello stream di dati del file PNG ed i suoi
campi sono vuoti.
– Dati ausiliari

Tutti i dati ausiliari sono opzionali, nel senso che gli encoder non hanno l'obbligo di scriverli ed i
decoder possono tranquillamente ignorarli.
Ad ogni modo, gli encoder sono invitati a scrivere dei dati ausiliari standard quando è possibile
ed i decoder sono invitati ad interpretare questi dati quando è possibile.
Parlerò dei vari dati ausiliari possibili di seguito, ad ogni modo, l'ordine in cui ne parlo
non è necessariamente l'ordine in cui compaiono in uno stream di dati PNG.

– Informazioni ausiliarie di trasparenza

Questo dato contiene le informazioni nello stream di dati che non include un canale alpha completo.

– tRNS

Il tRNS specifica che l'immagine utilizza una trasparenza semplice: i valori alpha associati alle
tavolozze in entrata (per le immagini a colori indexati) o i colori trasparenti singoli (per le immagini
in bianco e nero e quelle truecolor).
Anche se una trasparenza semplice non è efficiente come un canale alpha completo,
questa richiede meno spazio ed in molti casi è sufficiente.
Per il tipo di colore 3 (colori indexati), il tRNS contiene una serie di valori alpha di un byte
corrispondenti ai valori in entrata del PLTE.
Ogni entrata indica che pixel dell'indice di tavolozza corrispondente devono essere trattati come se
avessero il valore alpha specifico ed i valori alpha sono come quelli in un canale alpha completo ad
8 bit: 0 è completamente trasparente, 255 è completamente opaco,
a prescindere dalla profondità di bit dell'immagine.
Il tRNS non deve contenere più valori alpha dei dati di tavolozze in entrata, tuttavia ne può
contenere di meno; in quest'ultimo caso, tutti i valori rimanenti vengono considerati 255.
Per il tipo di colore 0 (bianco e nero), il tRNS contiene un solo valore di livello di grigio, del tipo:
Gray: 2 bytes, range 0. . .2^profondità di bit − 1

Se la profondità di bit è minore di 16, vengono utilizzati gli ultimi bit significativi e gli altri sono 0.
Pixel del livello di grigio specificato sono trattati come trasparenti (cioè come valore alpha 0),
mentre tutti gli altri pixel sono trattati come completamente opachi (valore alpha 2^profondità di bit
− 1).
Il tRNS è proibito per i tipi di colore 4 e 6, visto che è presente un canale alpha completo.
Quando si ha a che fare con bianchi e neri o dati truecolor da 16bit, è importante comparare
entrambi i byte dei valori dei campioni (sample) per determinare se un pixel è trasparente.
Ultimo appunto è che il tRNS, quando presente, deve precedere il primo dato IDAT e seguire il
PLTE, se presente.

– Informazioni dello spazio di colore

Questi dati sono relativi alla riproduzione dei campioni (sample) dell'immagine.

– Gamma dell'immagine gAMA

I dati gAMA specificano la relazione tra i campioni (sample) dell'immagine e l'intensità di


riproduzione in output desiderata: sample = light out^gamma
“sample” e “light_out” sono normalizzati nel range 0.0 (intensità minima), 1.0 (intensità massima).
Dunque:

Il valore è encodato come un intero unsigned di 4 byte.


Il valore di gamma non ha effetto sugli alpha sample,
che sono sempre una frazione lineare dell'opacità completa.
Se l'encoder non sa il valore di gamma dell'immagine, dovrebbe evitare di scrivere il dato gAMA.
Tecnicamente, “l'intensità di riproduzione in output desiderata” è ancora troppo “vago” come dato.
In altre parole, si devono specificare le condizioni di riproduzione in cui è desiderato.
Per il gAMA ci sono condizioni di riproduzione di referenza delle specifiche sRGB.
Aggiustare per le diverse condizioni di riproduzione è un procedimento complesso
e di solito è gestito dal CMS (Color Management System).
Se non viene fatto alcun aggiustamento, l'errore, di solito, è comunque piccolo.
Le applicazioni che richiedono un'alta fedeltà di colore potrebbero voler utilizzare un dato sRGB
o un dato iCCP ed analizzerò entrambi più avanti.
Se il gAMA è presente, deve precedere il primo dato IDAT e deve anche precedere il PLTE,
se presente.
Se sono presenti l'sRGB o l'iCCP, il dato gAMA viene sovrascritto.

– Cromaticità primarie cHRM

Le applicazioni che richiedono una specifica di colore indipendente dal device in un file PNG
possono utilizzare i dati cHRM per specificare le 1931 cromaticità CIE x, y di rosso, verde e blu
primarie utilizzate nell'immagine ed i punti bianchi di riferimento e contiene:

Ogni valore è encodato come intero unsigned di 4 byte.


Il cHRM è consentito in tutti i file PNG, sebbene sia di poca importanza
per le immagini in bianco e nero.
Se l'encoder non conosce i valori di cromaticità, dovrebbe evitare di scrivere il cHRM
e l'assenza di tale dato indica che i colori primari dell'immagine sono dipendenti dal device.
Se presente, il cHRM deve precedere il primo IDAT ed il PLTE, se presente.
Se presenti e riconosciuti, i dati sRGB e iCCP sovrascrivono il dato cHRM.

– sRGB, Spazio di colore standard per l'RGB

Se l'sRGB è presente, i sample dell'immagine sono conformi allo spazio di colore sRGB
e dovrebbero essere riprodotti utilizzando un rendering specifico.
L'sRGB contiene un dato di rendering che definisce 4 valori: percettivo, relativo alla colorimetrica,
della saturazione e colorimetrico assoluto.
Quello percettivo è per le immagini per le quali è preferibile un buon adattamento della gamma per
il device di output al costo di un accuratezza colorimetrica, come nelle fotografie.
Quello relativo alla colorimetrica è per le immagini che richiedono che l'apparenza dei colori sia
fedele, tipo i loghi.
Quello della saturazione è per le immagini per le quali è preferibile preservare la saturazione al
costo di un accuratezza in hue e luminosità, come nei grafici.
Quello colorimetrico assoluto è per le immagini per le quali è necessario preservare
una colorimetrica assoluta.
Un'applicazione che scrive un dato sRGB dovrebbe anche scriverne uno gAMA (e, magari, anche
un cHRM) per compatibilità con le applicazioni che non sono in grado di utilizzare l'sRGB stesso.
Se presente, le applicazioni che riconoscono l'sRGB e sono capaci della gestione del colore,
ignorano i dati relativi a gAMA e cHRM.
Tale dato deve precedere il primo dato IDAT ed il PLTE, se presente.
Ricordo infine che l'sRGB e l'iCCP non dovrebbero comparire insieme.

– iCCP, profilo ICC integrato

Se il dato iCCP è presente, i sample dell'immagine sono conformi allo spazio di colore e vengono
rappresentate dal profilo ICC integrato.
Lo spazio di colore del profilo ICC dev'essere RGB per le immagini del tipo di colore 2, 3 e 6
o in bianco e nero per il tipo di colore 0 e 4 (scala di grigi).
L'iCCP contiene il nome del profilo (una stringa di caratteri da 1 a 79 byte),
il “null separator” di 1 byte, il metodo di compressione di 1 byte ed il profilo compresso di n byte.
Il nome del profilo può essere qualsiasi cosa; è case sensitive e soggetto alle stesse restrizioni delle
parole chiave in un dato di tipo testo di cui ho parlato sopra.
Un'applicazione che scrive l'iCCP, dovrebbe anche scrivere il gAMA ed il cHRM che approssimano
la funzione del profilo ICC, per compatibilità con le applicazioni che non sono in grado di utilizzare
l'iCCP.
Se presente, le applicazioni che sono in grado di riconoscere l'iCCP e che sono capaci della gestione
del colore dovrebbero ignorare il gAMA ed il cHRM, tuttavia, se non sono in grado di effettuare
una gestione del colore completa, dovrebbero utilizzare il gAMA ed il cHRM, se presenti.
Un file dovrebbe contenere al massimo un profilo integrato, che sia esplicito come l'iCCP
o implicito come l'sRGB.
Se l'iCCP è presente, deve precedere il primo IDAT ed il PLTE, se presente.

– Informazioni testuali (tEXt, zTXt e iTXt)

I dati tEXt, zTXt e iTXt sono utilizzati per le informazioni testuali associate con l'immagine,
ma mi riferirò a tutti e tre come “informazioni testuali” per semplicità,
dopodiché li analizzerò separatamente.
Ogni dato di testo contiene come primo campo una parola chiave che indica il tipo di informazione
rappresentata dalla stringa di testo.
Le parole chiave riportate di seguito sono predefinite e dovrebbero essere utilizzate,
quando opportuno:

Title: titolo o nome dell'immagine.


Author: nome dell'autore dell'immagine.
Description: descrizione dell'immagine.
Copyright: copyright dell'immagine.
Creation Time: quando è stata creata l'immagine originale.
Software: il software utilizzato per creare l'immagine.
Disclaimer: disclaimer.
Warning: avvertimento sulla natura del contenuto.
Source: il device utilizzato per creare l'immagine.
Comment: commenti vari (conversione dal commento dei GIF).

1) tEXt

Le informazioni testuali che l'encoder vuole registrare assieme all'immagine sono salvate nei dati
tEXt.
Ogni dato tEXt contiene una parola chiave, una stringa di testo nel formato:

La parola chiave e la stringa di testo sono separate da uno zero byte (null) e né la prima né la
seconda possono contenere valori nulli; da notare che la stringa di testo, invece, non è terminata da
un “null”.

2) zTXt

Anche lo zTXt contiene dati di tipo testuale – così come il tEXt – ma trae vantaggio dalla
compressione.
Per tutto il resto, sono semanticamente equivalenti, ma è comunque consigliato lo zTXt se si ha a
che fare con lunghe porzioni di testo.
Lo zTXt contiene:

La parola chiave ed il null separator sono esattamente gli stessi del tEXt,
dunque la parola chiave non è compressa.
Il metodo di compressione identifica il metodo utilizzato e l'unico valore attualmente definito
è lo zero ed il byte del metodo di compressione è infine seguito da uno stream di dati compresso.

3) iTXt

L'iTXt è semanticamente equivalente al tEXt ed allo zTXt, ma il testo è scritto in UTF-8 Unicode
invece del Latin-1 utilizzato dai precedenti due e contiene:

La parola chiave è la stessa dello zTXt.


Il compression flag è 0 per il testo non compresso ed 1 per il testo compresso e solo il campo “text”
può essere compresso.
Per il testo non compresso, l'encoder dovrebbe impostare il metodo di compressione a zero
ed il decoder dovrebbe semplicemente ignorarlo.
Il language tag indica il linguaggio umano utilizzato per tradurre la parola chiave ed il testo.
A differenza della parola chiave, il language tag è case sensitive.
È una stringa di caratteri ASCII del tipo (it, en-us, en-uk, cn ecc.).
Se il language tag è vuoto, la lingua non è specificata.
Il campo translated keyword ed il campo text utilizzano entrambi l'UTF-8 Unicode ed il testo,
a differenza degli altri, non ha un null separator.

– bKGD, colore di background

Il dato bKGD specifica un colore di background di default per rappresentare l'immagine, tuttavia,
gli utenti non sono tenuti a seguire tale dato e possono tranquillamente scegliere di utilizzare un
background differente.
Per il tipo di colore 3 (colori indexati), il bKGD contiene un index di tavolozza di 1 byte ed altro
non è che il valore del colore da utilizzare come background.
Per i tipi di colore 0 e 4 (bianco e nero con e senza alpha), il bKGD contiene:

Se la profondità di bit dell'immagine è minore di 16, vengono utilizzati i bit meno significativi e gli
altri sono 0.
Tale valore altro non è che il livello di grigio utilizzato come background.
Per i tipi di colore 2 e 6 (truecolor con e senza alpha), il bKGD contiene:

Se la profondità di bit dell'immagine è minore di 16, vengono utilizzati i bit meno significativi e gli
altri sono 0.
Tale valore altro non è che il colore RGB da utilizzare come background.
Quando presente, il dato bKGD deve precedere il primo dato IDAT e deve seguire il PLTE, se
presente.

– pHYs, dimensioni fisiche del pixel

I dati di pHYs specificano la dimensione dei pixel desiderata o l'aspect ratio per la riproduzione
dell'immagine.

E per lo unit specifier sono definiti i seguenti valori:

Quando lo unit specifier è 0, il pHYs definisce solamente l'aspect ratio,


mentre la grandezza dei pixel rimane non specificata.
Se questo dato ausiliario non è presente, i pixel vengono trattati come quadrati
e la dimensione fisica di ogni pixel rimane sconosciuta.
Se è presente, invece, deve precedere il primo dato IDAT.

– sBIT, bit significativi


L'sBIT è utilizzato per memorizzare il numero originale di bit significativi, consentendo così ai
decoder di recuperare il dato originale in maniera lossless anche se tale dato ha un sample depth
non direttamente supportato dal PNG.
Per il tipo di colore 0 (bianco e nero), l'sBIT contiene un singolo byte
che indica il numero di bit significativi nel dato di origine.
Per il tipo di colore 2 (truecolor), l'sBIT contiene tre byte che indicano il numero di bit significativi
nel dato di origine rispettivamente per i canali rosso, verde e blu.
Per il tipo di colore 3 (colori indexati), l'sBIT contiene tre byte che indicano il numero di bit
significativi nel dato di origine rispettivamente per i componenti rosso, verde e blu
dei valori in entrata della tavolozza.
Per il tipo di colore 4 (bianco e nero con canale alpha), l'sBIT contiene due byte che indicano il
numero di bit significativi rispettivamente nel dato di origine in bianco e nero
e nel dato di origine in alpha.
Per il tipo di colore 6 (truecolor con canale alpha), l'sBIT contiene quattro byte che indicano il
numero di bit significativi rispettivamente nel dato di origine rosso, verde e blu
e nel dato di origine in alpha.
Ogni profondità specificata nell'sBIT deve essere più grande di zero e minore o uguale alla
profondità del sample (che è 8 per le immagini a colori indexati e la cui profondità è data dall'IHDR
per gli altri tipi di colore).
Se l'sBIT è presente, deve precedere il primo dato IDAT ed il PLTE, se presente.

– sPLT, tavolozza suggerita

Questo dato può essere utilizzato per suggerire una tavolozza ridotta da usare quando il device che
deve riprodurre l'immagine non è capace di riprodurre il range completo di colori
presenti nella stessa.
Se presente, fornisce un set di colori consigliato con l'alpha e le informazioni di frequenza
da poter usare per costruire una tavolozza ridotta con cui l'immagine PNG può essere quantizzata.
Questo dato contiene una stringa di testo terminata da un null che dà il nome alla tavolozza ed un
sample depth da un byte, seguito da una serie di valori in ingresso alla tavolozza ed ogni serie di 6
o 10 byte contiene cinque interi unsigned:

Il decoder determina il numero dei valori in entrata dalla lunghezza dei dati rimanenti dopo il byte
del sample depth e, se non è divisibile per 6 (se il sample depth dell'sPLT è 8) o 10 (se il sample
dapth dell'sPLT è 16), allora risulterà in un errore.
I valori in ingresso devono comparire in ordine decrescente di frequenza e non è richiesto
che debbano essere utilizzati nell'immagine, né che siano tutti differenti.
Il nome della tavolozza (palette name) può essere un nome qualsiasi che si riferisce alla tavolozza e
può essere utile alle persone per scegliere la giusta tavolozza suggerita quando ce ne sono diverse
nel file PNG.
Il nome della tavolozza è case sensitive ed è soggetto alle stesse restrizioni delle parole chiave.
Il sample depth dell'sPLT dev'essere 8 o 16.
I sample rosso, verde, blu ed alpha sono possono essere di uno o di due byte ciascuno,
a seconda del sample depth dell'sPLT, a prescindere dalla profondità di bit dell'immagine.
I sample del colore non sono pre-moltiplicati dall'alpha,
tantomeno sono pre-compositi su alcun background.
Un valore alpha di zero significa completamente trasparente, mentre un valore alpha di 255 (quando
il sample depth dell'sPLT è 8) o di 65535 (quando il sample depth dell'sPLT è 16)
significa completamente opaco.
I sample della tavolozza hanno gli stessi valori di gamma e cromaticità
di quelli dell'immagine PNG.
Ogni valore di frequenza è proporzionale alla frazione dei pixel dell'immagine più vicini ai valori
di ingresso della tavolozza nello spazio RGBA, prima che l'immagine sia composta
su qualche background.
L'esatto fattore di scala è scelto dall'encoder, ma dovrebbe essere scelto in modo che il range dei
valori individuali riempia ragionevolmente il range da 0 a 65535.
È accettabile aumentare artificialmente le frequenze per colori “importanti” tipo quelli del logo
di una compagnia.
Zero è considerata una frequenza valida e significa che il colore è “meno importante” o che,
se usato, è usato raramente.
Ad ogni modo, quando tutte le frequenze sono zero, diventano inutili in quanto niente
può essere dedotto sulle frequenze attuali dei colori.
L'sPLT può essere presente in qualsiasi tipo di colore nel PNG.
Da notare che i valori in entrata dell'sPLT possono essere esterni allo spazio di colore dell'immagine
PNG; ad esempio, in un'immagine PNG in bianco e nero, i valori in entrata sPLT
probabilmente soddisfaranno R=G=B anche se non è richiesto.
La stessa cosa vale se consideriamo l'alpha, difatti i valori in entrata sPLT possono avere valori
alpha non opachi anche quando l'immagine PNG non utilizza la trasparenza.
Se l'sPLT è presente, deve precedere il primo dato IDAT.
Possono esserci più dati sPLT, ma, in tal caso, devono per forza avere nomi di tavolozza diversi.

– hIST, istogramma di tavolozza

Il dato hIST rappresenta la frequenza di utilizzo approssimativa di ogni colore


nella tavolozza di colori.
Un dato hIST può comparire solo se è presente il PLTE.
Se il riproduttore non è in grado di provvedere a tutti i colori della tavolozza,
l'istogramma può aiutare a decidere quale subset di colori scegliere per la riproduzione.
L'hIST contiene una serie di interi unsigned di 2 byte (16 bit).
Ci dev'essere esattamente un valore in entrata per ogni valore in entrata nel PLTE.
Ogni valore in entrata è proporzionale alla frazione dei pixel nell'immagine
che hanno quell'indice di tavolozza; l'esatto fattore di scala è scelto dall'encoder.
I valori in entrata dell'istogramma sono approssimati, con l'eccezione che un valore in entrata zero
specifica che il corrispondente valore in entrata della tavolozza non è utilizzato nell'immagine.
È richiesto che un valore in ingresso all'istogramma sia diverso da zero
se ci sono dei pixel di quel colore.
Quando la tavolozza è una quantizzazione suggerita di un'immagine truecolor, l'istogramma è
necessariamente approssimato, dato che il decoder potrebbe mappare i pixel ai valori in ingresso
della tavolozza diversamente rispetto a come ha fatto l'encoder;
in questo caso, non dovrebbero comparire valori in ingresso zero.
Il dato hIST, se presente, deve seguire il PLTE e deve precedere il primo dato IDAT.
– tIME, data dell'ultima modifica dell'immagine

Il dato tIME fornisce la data dell'ultima modifica dell'immagine e non della creazione
dell'immagine iniziale.
Contiene 2 byte per l'anno (che è completo, tipo 1993 e non '93), 1 byte per il mese (che va da 1 a
12), 1 byte per il giorno (che va da 1 a 31), 1 byte per l'ora (che va da 0 a 23), 1 byte per il minuto
(che va da 0 a 59) ed un byte per il secondo (che va da 0 a 60).
Il tempo viene generalmente indicato in UTC (Universal Time) e non nel fuso locale
e si aggiorna automaticamente ogni qual volta che l'immagine viene modificata.

– Compressione diminuita/aumentata

Il metodo di compressione del PNG 0 (l'unico attualmente definito per il PNG)


specifica una compressione diminuita od aumentata con un margine di massimo 32768 byte.
La compressione diminuita è una derivata LZ77 utilizzata nello zip, nel gzip, nel pkzip
ed altri programmi.
Gli stream di dati a compressione diminuita del PNG sono salvati nel formato “zlib”
che ha la seguente struttura:

Per il metodo di compressione del PNG 0, il compression method/flags code deve specificare il
codice di metodo 8 (compressione diminuita) ed il margine dell'LZ77
non deve essere superiore a 32768 byte.
Da notare che il numero del metodo di compressione non è lo stesso del PNG:
i flag aggiuntivi non devono specificare un dizionario presente.
Il decoder PNG dev'essere in grado di decomprimere ogni stream di dati zlib valido
che soddisfi questi vincoli aggiuntivi.
Se il dato da comprimere contiene 16384 byte o meno,
l'encoder può settare il margine arrotondando ad una potenza di 2 (minimo 256).
Così facendo, viene diminuita la memoria richiesta non solo per l'encoding,
ma anche per il decoding, senza intaccare negativamente il rapporto di compressione.
Il dato compresso nello stream di dati zlib è salvato in una serie di blocchi, ognuno dei quali può
rappresentare un dato raw (non compresso), un dato LZ77 compresso encodato con una codifica di
Huffman fissata o un dato LZ77 compresso encodato con una codifica di Huffman personalizzata.
L'ultimo blocco è identificato da un marcatore nel suo bit finale e consente al decoder
di riconoscere la fine dello stream di dati compresso.
Il check value salvato alla fine dello stream di dati zlib è calcolato sui dati non compressi
rappresentati dallo stream di dati.
Da notare che l'algoritmo utilizzato non è lo stesso del CRC utilizzato per il check value del PNG.
Il check value dello zlib è utile più che altro come controllo incrociato
che gli algoritmi di compressione diminuita od aumentata siano implementati correttamente.
Verificando i dati, il CRC conferisce una sicurezza abbastanza alta che il dato di immagine PNG
è stato trasmesso correttamente.
In un file PNG, la concatenazione dei contenuti di tutti i dati IDAT crea uno stream di dati zlib,
come specificato sopra.
È importante ricordare che i bordi tra i dati IDAT sono arbitrari e possono trovarsi ovunque nello
stream di dati zlib.
Non c'è alcuna correlazione necessaria tra i bordi dei dati IDAT ed i bordi dei blocchi di
compressione diminuita; ad esempio, è perfettamente possibile che il check value finale dello zlib
sia diviso tra i dati IDAT.
D'altro canto, non c'è alcuna correlazione richiesta tra la struttura dei dati dell'immagine (ovvero i
bordi delle linee di scansione) ed i bordi dei blocchi di codifica diminuita o dei bordi dei dati IDAT.
Il dato dell'immagine completo è rappresentato da un singolo stream di dati zlib
che è salvato in alcuni numeri dei dati IDAT.
Il PNG utilizza inoltre lo stream di dati zlib per i dati iTXt, zTXt ed iCCP, dove il resto dei dati
successivi al byte del metodo di compressione è uno stream di dati zlib, come specificato sopra.
A differenza del dato di immagine, tali stream di dati non sono divisi: ogni dato iTXt, zTXt o iCCP
contiene uno stream di dati zlib indipendente.

– Tipi di filtri

Come già detto varie volte sopra, l'unico metodo di filtraggio attualmente definito è il metodo 0 e
questo definisce 5 tipi di filtro base numerati da 0 a 4:

Da notare che il metodo 0 nell'IHDR specifica esattamente questo set di cinque tipi di filtro.
Se il set dei tipi di filtro è esteso, viene assegnato un metodo di filtraggio diverso al set esteso,
in modo che i decoder non abbiano bisogno di decomprimere i dati
per scoprire che contengono un tipo di filtro non supportato.
Ad ogni modo, tornando a noi, l'encoder può scegliere quale di questi algoritmi di filtraggio
applicare in un procedimento “linea di scansione per linea di scansione”.
Nel dato dell'immagine inviato nel passo di compressione, ogni linea di scansione è preceduta da un
byte del tipo di filtro che specifica l'algoritmo di filtraggio utilizzato per tale linea di scansione.
Gli algoritmi di filtraggio sono applicati ai byte (e non ai pixel), a prescindere dalla profondità di bit
o dal tipo di colore dell'immagine.
L'algoritmo di filtraggio funziona sulla sequenza di byte formata da una linea di scansione che è
stata rappresentata come descritto sopra nella sezione relativa al “layout delle immagini”.
Se l'immagine include un canale alpha, i dati alpha sono filtrati nello stesso modo
dei dati dell'immagine.
Quando un'immagine è interlacciata, ogni passo del pattern di interlacciamento
è trattato come immagine indipendente per il filtraggio.
I filtri funzionano sulla sequenza di byte formata dai pixel attualmente trasmessi durante un passo
e la linea di scansione precedente è quella trasmessa precedentemente nello stesso passo
e non quella adiacente nell'immagine completa.
Da notare che la sotto-immagine trasmessa in un passo è sempre rettangolare,
ma ha larghezza e/o altezza minori rispetto all'immagine completa.
Inoltre, il filtraggio non è applicabile quando questa sottoimmagine è vuota.
Per tutti i filtri, il byte “da sinistra” al primo pixel nella linea di scansione
dev'essere trattato come se fosse zero.
Per i filtri che si rifanno alla linea di scansione precedente, l'intera linea di scansione precedente
dev'essere tratta come se fosse zero per la prima linea di scansione di un immagine (o per un passo
di un'immagine interlacciata).
Per fare il procedimento inverso, il decoder deve utilizzare i valori decodificati del pixel precedente
della stessa linea di scansione, il pixel immediatamente precedente al pixel corrente sulla linea
precedente ed il pixel a sinistra del pixel precedente.
Anche se alcuni tipi di filtro non si rifanno alla linea di scansione precedente, il decoder avrà
comunque sempre bisogno di salvare ogni linea di scansione appena decodificata, dato che la linea
di scansione successiva potrebbe utilizzare un filtro che si rifà a quest'ultima.
Il PNG non impone restrizioni su che tipo di filtro applicare ad una immagine, tuttavia,
i filtri non sono egualmente efficienti su tutti i tipi di dato.

0) Filter type 0, None

Con il None(), la linea di scansione è trasmessa senza alcuna modifica;


se necessario, viene inserito solamente un byte tipo di filtro prima del dato.

1) Filter type 1, Sub

Il Sub() trasmette la differenza tra ogni byte ed il valore del byte corrispondente del pixel
precedente e viene applicata la seguente formula ad ogni byte della linea di scansione:
Sub(x) = Raw(x) – Raw(x-bpp)
dove x può assumere valori che vanno da zero
al numero di byte rappresentanti la linea di scansione, meno 1.
Il Raw() si riferisce al byte del dato raw a quel byte di posizione nella linea di scansione.
Il Bpp è definito come il numero di byte per pixel completo, approssimato ad uno.
Ad esempio, per il tipo di colore 2 con una profondità di bit di 16,
il bpp è uguale a 6 (3 sample, due byte per sample).
Per il tipo di colore 0 con una profondità di bit di 2, il bpp sarà uguale ad 1
(per via dell'arrotondamento).
Per il tipo di colore 4 con una profondità di bit di 16, invece, il bpp sarà uguale a 4
(sample in bianco e nero da due byte ed un alpha sample da 2 byte).
Da notare che questo procedimento è effettuato per ogni byte, a prescindere dalla profondità di bit.
In un'immagine a 16 bit, ogni MSB è predetto dall'MSB precedente ed ogni LSB dall'LSB
precedente, proprio per il modo in cui è definito il bpp.
Viene utilizzato il modulo aritmetico unsigned 256 in modo che tutti i valori entrino in 8 bit
e non ci sia overflow e la sequenza dei valori Sub è trasmessa come la linea di scansione filtrata.

Per effettuare invece il processo inverso del filtro Sub() dopo la decompressione,
si ha il seguente valore in output:

(modulo 256 computato), dove Raw() si riferisce al numero di byte già decodificati.

2) Filter type 2, Up

Il filtro Up() è esattamente come il Sub() eccetto per il fatto che vengono utilizzati per la predizione
i pixel immediatamente precedenti al pixel corrente e non solo quelli alla sua destra,
come accadeva invece nel Sub.
Per computare il filtro Up(), si applica la seguente formula ad ogni byte della linea di scansione:

dove x può assumere valori che vanno da zero al numero di byte rappresentanti la linea di scansione
meno 1.
Il Raw() si riferisce al byte del dato raw a quel byte di posizione nella linea di scansione.
Il Prior(x) si riferisce ai byte non filtrati della linea di scansione precedente.
È doveroso ricordare che questo viene fatto per ogni byte, a prescindere dalla profondità di bit.
Viene utilizzato anche qui il modulo aritmetico 256 unsigned, in modo che tutti i valori entrino in 8
bit e non ci sia overflow e la sequenza dei valori Up è trasmessa come linea di scansione filtrata:
nella prima linea di scansione di un'immagine (o di un passo, se interlacciata),
si suppone che Prior(x) sia uguale a 0 per ogni x.
Per effettuare il processo inverso del filtro Up() dopo la decompressione,
si ha il seguente valore in output:

(modulo 256 computato), dove Prior() si riferisce ai byte decodificati della linea di scansione
precedente.

3) Filter type 3, Average

Il filtro Average() utilizza l'average (la media) dei due pixel vicini (sinistro e precedente)
per predire il valore di un pixel.
Per computare il filtro Average(), si applica la seguente formula ad ogni byte della linea di
scansione:

dove il risultato è il modulo 256 computato, ma la predizione è calcolata nello stesso modo
dell'encoding.
Raw() si riferisce ai due byte già decodificati ed il Prior() si riferisce ai byte decodificati
della linea di scansione precedente.

4) Filter type 4, Paeth

Il filtro Paeth computa una semplice funzione lineare dei tre pixel vicini (sinistro, precedente,
superiore sinistro), poi sceglie come predizione il pixel vicino più vicino al valore computato.

Per computare il filtro Paeth(), si applica la seguente formula ad ogni byte della linea di scansione:

dove x assume valori che vanno da zero


al numero di byte rappresentante la linea di scansione meno 1.
Il Raw() si riferisce al byte del dato raw a quel byte di posizione nella linea di scansione.
Il Prior() si riferisce ai byte non filtrati della linea di scansione precedente.
Il bpp è definito come il numero di byte per pixel completo, approssimato ad uno,
esattamente come già detto quando stavo trattando il Sub().
Da notare che questo è fatto per ogni byte, a prescindere dalla profondità di bit
e che il modulo aritmetico unsigned 256 viene utilizzato in modo che tutti i valori entrino in 8 bit
e non ci sia overflow.
La sequenza di valori Paeth è trasmessa come linea di scansione filtrata.

La funzione di PaethPredictor() è definita dal seguente pseudo-codice:


I calcoli all'interno della funzione PaethPredictor() devono essere fatti in modo esatto e senza
overflow ed il modulo aritmetico 256 è utilizzato solamente per la fase finale di sottrazione del
risultato della funzione dal valore di byte desiderato.
Per ogni x < 0, si considera che Raw(x) sia uguale a 0 e Prior(x) sia uguale zero.
Nella prima linea di scansione di un'immagine (o di un passo se interlacciata),
si considera che Prior(x) sia uguale a 0 per ogni x.
Per effettuare il processo inverso del filtro Paeth dopo la decompressione,
il valore in output è dato da:

(modulo 256 computato), dove Raw() e Prior() si riferiscono ai byte già decodificati
e la stessa funzione PaethPredictor() è utilizzata sia dall'encoder che dal decoder.

– Regole di ordinamento dei dati

Per consentire ai nuovi tipi di dato di essere aggiunti allo standard PNG, è necessario porre delle
regole relative all'ordinamento degli stessi, altrimenti un programma qualsiasi che incontra un dato
sconosciuto nel file PNG, non avrà idea del da farsi.
Definiamo un “editor PNG” un programma in grado di modificare un file PNG e che cerca di
preservare più dati ausiliari possibile.
Due esempi di editor PNG sono un programma che aggiunge o modifica dati di testo
ed un programma che aggiunge una tavolozza suggerita ad un'immagine truecolor in PNG.
Gli editor di immagini ordinari non sono editor PNG in questo senso, perché di solito
non mantengono tutte le informazioni non riconosciute mentre leggono un'immagine.
Come esempio dei possibili problemi, consideriamo un ipotetico nuovo tipo di dato ausiliario
che è “sicuro da copiare” che deve comparire dopo il PLTE, se presente.
Se il programma – per aggiungere un PLTE suggerito – non riconosce questo nuovo dato,
potrebbe inserire il PLTE nel posto sbagliato, ovvero dopo il nuovo dato!
Sarebbe possibile prevenire tale problema richiedendo agli editor PNG di cancellare tutti i dati
non riconosciuti, ma non è esattamente l'approccio ottimale.
Per evitare tutto questo, sono state poste alcune restrizioni sia di comportamento degli editor,
sia sull'ordine dei dati.

Tali restrizioni sono:

1) Quando viene copiato un dato ausiliario sconosciuto “non sicuro da copiare”, l'editor PNG
deve evitare di muovere qualsiasi dato critico. Può ri-allocare i dati relativi agli altri dati a
suo piacimento, ma non quelli critici. L'editor non può aggiungere, eliminare, modificare
o riordinare i dati critici se sta preservando dati non riconosciuti “non sicuri da copiare”.
2) Quando viene copiato un dato ausiliario sconosciuto “sicuro da copiare”, l'editor PNG deve
evitare di muovere i dati da prima dell'IDAT a dopo l'IDAT (o vice versa),
ogni altra ri-allocazione è permessa.

3) Quando viene copiato un dato ausiliario conosciuto, l'editor deve rispettare le regole di
ordinamento relative a quel tipo di dato.

4) Gli editor PNG devono bloccare l'editing se incontrano un tipo di dato non riconosciuto
catalogato come “critico”. Questo perché non è possibile sapere se la modifica del file
contenente tale dato darà un file risultante corretto. A prima vista potrebbe essere
ragionevole pensare di eliminarlo semplicemente per risolvere il problema, tuttavia non è
possibile farlo perché tale dato potrebbe comunque essere importante per l'interpretazione di
altri dati!

Per quanto riguarda invece l'ordinamento dei tipi di dato, si hanno due regole di base:

1) I dati non sicuri da copiare possono avere requisiti di ordinamento relativi a dati critici.
2) I dati sicuri da copiare possono avere requisiti di ordinamento relativi all'IDAT.

– Comparazione con GIF e JPEG

Ora che siamo arrivati ad avere un quadro completo e dettagliato dello standard più utilizzato per la
diffusione di immagini su internet (il PNG), è il momento di tirare le somme
e compararlo al suo predecessore (il GIF) ed al suo rivale lossy (il JPEG).
Il PNG, inoltre, consente una gamma di trasparenza maggiore del GIF.
Inoltre, mentre il GIF è limitato ai colori indexati ad 8 bit,
il PNG consente un più ampio raggio di profondità di colore,
incluso il 24-bit (8 bit per canale) ed il 48-bit (16 bit per canale) truecolor,
consentendo una precisione maggiore.
Non solo, considerando il canale alpha, si possono avere fino a 64 bit per pixel
(prima della compressione).
Se un'immagine viene convertita da PNG in GIF ed ha più di 256 colori,
l'immagine risultante in GIF potrebbe soffrirne a causa della posterizzazione.
Per capirne l'effetto, prendiamo in esame la seguente immagine.
La prima ha 24 bit (quindi 16.7 milioni di colori), mentre la seconda è stata ridotta a 256 colori.
È comunque doveroso ricordare che il GIF supporta nativamente le immagini animate, mentre il
PNG no. Per quanto concerne la versione “animata” del PNG che è possibile trovare su internet,
è assolutamente non ufficiale.
Anni fa era possibile dire che il PNG non fosse supportato in maniera capillare,
basti pensare che Internet Explorer 6 lo supportava solo in parte, tuttavia ad oggi non è più così,
infatti browser moderni come Google Chrome (ed i browser derivati da esso come Microsoft Edge)
e Firefox lo supportano senza problemi, così come i lettori di default integrati in Windows 10,
Linux Fedora e Mac OSX.

Per quanto riguarda il JPEG, invece, questo può produrre immagini più piccole a seconda del passo
di quantizzazione utilizzato (visto che utilizza un metodo lossy e quindi viene tagliato via dettaglio),
tuttavia è bene ricordare che il JPEG non supporta l’alpha channel, cioè la trasparenza.
2.5) SSIM – Una metrica oggettiva per comparare la qualità

Per effettuare una comparazione oggettiva tra i codec analizzati (GIF, JPG, JPG2000, PNG) è stato
utilizzato l’SSIM (Structural Similarity Index Measure). L’SSIM è un metodo di predizione della
qualità percepita delle immagini a riferimento completo, ovvero misura / predice la qualità di una
immagine compressa usando come riferimento la stessa immagine non compressa (e quindi priva di
distorsione) come riferimento. L’SSIM è un modello basato sulla percezione che considera il
degradamento di un’immagine come cambiamento percepito nell’informazione strutturale,
incorporando allo stesso tempo importanti fenomeni di percezione, includendo sia il masking del
luma che del contrasto. Per “informazione strutturale” si intende l’idea che i pixel abbiamo una
forte inter-dipendenza, specialmente quando sono vicini. Queste dipendenze portano con loro
informazioni importanti sulla struttura degli oggetti nella scena visualizzata. Il masking del luma è
il fenomeno in cui le distorsioni di una immagine tendono ad essere meno visibili nelle zone più
luminose, mentre il masking del contrasto è un fenomeno in cui le distorsioni diventano meno
visibili nelle zone in cui c’è una attività significativa (o “texture”) nell’immagine.
L’index SSIM è calcolato su varie finestre di un’immagine. La misura tra due finestre x ed y di
grandezza comune NxN è:

dove μx è la media di x, μy è la media di y, è la varianza di x, è la varianza di y, σxy è la


covarianza di x ed y, L è il range dinamico dei valori dei pixel (2^bpp -1), k1=0,01, k2=0,03 e
sono due variabili che servono a stabilizzare la divisione con il denominatore
debole. La formula è basata su tre misure di comparazione tra i sample di x ed y: luma (l), contrasto
(c) e struttura (s). Le funzioni di comparazione individuali sono:

con c3 = c2/2.
L’SSIM è quindi una combinazione pesata di queste misure di comparazione:

Ponendo i pesi α, β, γ uguali ad 1, la formula può essere ridotta alla forma mostrata sopra.
I valori dell’SSIM partono da 0 ed arrivano ad un massimo di 1, dove più il valore è vicino a 0, più
l’immagine compressa risulta distorta e con differenze rispetto a quella originale e più è vicino ad 1
più l’immagine è simile all’originale. Nel caso dei codec lossless (quindi privi di perdita), il
punteggio sarà chiaramente 1 in quanto l’immagine decodificata dal nuovo codec dopo l’encoding
rappresenta esattamente l’immagine di partenza che può essere quindi riprodotta senza distorsione.
L’SSIM soddisfa l’identità di indiscernibilità (principio degli indiscernibili) e le proprietà di
simmetria, ma non la disuguaglianza triangolare né la non negatività e quindi non è una funzione di
distanza. Utilizzando una source in TIFF lossless 2048x858 yv12 (4:2:0 planar) 8bit, è stata
effettuata la conversione in GIF, JPEG, JPEG2000 e PNG utilizzando il miglior passo di
quantizzazione nel caso dei codec lossy (GIF, JPEG, JPEG2000) e la migliore compressione nel
caso del codec lossless (PNG) ed ognuna delle immagini è stata comparata all’originale utilizzando
l’SSIM per le singole componenti di luma (Y) e chroma (U e V).
I risultati ottenuti sono stati i seguenti:

Codec Punteggio SSIM Y Punteggio SSIM U Punteggio SSIM V


GIF 0.7893 0.9907 0.9854
JPEG 0.9967 0.9977 0.9971
JPEG2000 0.9983 0.9985 0.9980
PNG 1.0000 1.0000 1.0000

Il valore complessivo dell’SSIM per ognuno dei Codec è GIF SSIM 0.8290, JPEG SSIM 0.9969,
JPEG2000 SSIM 0.9983, PNG SSIM 1.0000

Risulta quindi evidente che il fatto di essere limitato ad una palette di 256 colori rappresenti un
grosso limite per il GIF e, tale limite, penalizza il risultato finale ottenuto utilizzando tale metodo di
compressione. Per quanto riguarda il JPEG, questo è riuscito ad ottenere una rappresentazione
abbastanza fedele dell’immagine originale, tuttavia l’utilizzo della Trasformata Discreta del Coseno
e la divisione in blocchi di pixel ha causato delle leggere differenze tra i blocchi che hanno
penalizzato il risultato finale in favore del JPEG2000 che ha invece utilizzato la Trasformata di
Wavelet su tutta l’immagine. Infine, come risultato migliore troviamo il PNG che, essendo lossless,
ha riprodotto l’immagine originale in maniera fedele e senza introdurre alcun tipo di distorsione,
ottenendo così punteggio massimo. Questo, ovviamente, avviene a discapito delle dimensioni del
file, ovviamente, che richiede dunque più bitrate.
Le dimensioni del file originale in TIFF sono 7.4 MB, quelle del PNG sono 5.3 MB, mentre quelle
del JPEG2000 che è lossy sono 4.0 MB.
3.0.0) Basi della codifica video
Prima di andare a parlare dell'utilizzo delle trasformate nei codec di codifica video,
è doveroso introdurre le basi della codifica video.

– 3.0.1) Scene video naturali

Una scena video del mondo reale (o “naturale”) è composta da molteplici oggetti, ognuno con una
propria forma caratteristica, la propria profondità, la propria texture ed illuminazione.
I colori e la luminosità di una scena video naturale cambiano con diversi gradi di intensità tra le
scene (tono continuo).
Le caratteristiche di una scena video naturale rilevanti per la compressione includono
le caratteristiche spaziali (variazione delle texture all'interno della scena, numero e forma
degli oggetti, i colori e così via) e le caratteristiche temporali (movimento degli oggetti,
cambiamenti nell'illuminazione, movimenti della videocamera, punto di vista e così via).
Una scena video naturale è continua sia spazialmente che temporalmente.
Rappresentare una scena visiva in forma digitale comporta fare il sampling (campionamento)
spaziale della scena reale (solitamente in una griglia rettangolare nel piano dell'immagine video)
e temporale (come una serie di immagini fisse o componenti di frame
campionate ad intervalli di tempo regolari).
Un video digitale è la rappresentazione di una scena di video campionato in forma digitale.
Ogni sample spazio-temporale (elemento dell'immagine o pixel) è rappresentato come un numero
od un set di numeri che descrivono il luma ed il chroma del sample.

Per ottenere un'immagine bidimensionale campionata, la videocamera concentra la proiezione


bidimensionale della scena video in un sensore, come un array CCD (Charge Coupled Devices).
Nel caso di cattura di immagine a colori, ogni componente di colore è filtrata separatamente
e proiettata in un array CCD.
L'output di un array CCD è un segnale video analogico,
un segnale elettrico che rappresenta un'immagine video.
Campionando il segnale in un punto in un tempo si ottiene un'immagine campionata
od un frame che ha valori definiti ad un set di punti di campionamento.
Il formato più comune per un'immagine campionata è un rettangolo
con i punti di campionamento posizionati in una griglia quadrata o rettangolare.
La figura rappresentata mostra un frame a tono continuo con due diverse griglie di campionamento.
Il campionamento si verifica ad ogni punto di intersezione sulla griglia e l'immagine campionata
può essere ricostruita rappresentando ogni sample (campione) come un elemento quadrato
dell'immagine (pixel).
La qualità visiva dell'immagine è influenzata dal numero di punti di campionamento.
Scegliere una griglia di campionamento “grossolana” avrà l'effetto di produrre un'immagine
campionata a bassa risoluzione, mentre una griglia di campionamento efficiente (con tanti punti),
produrrà un'immagine decisamente più accurata.
Per questo test sono state utilizzate due griglie: la prima è quella nera (grossolana)
e la seconda è quella grigia (più accurata), rappresentate nell'immagine soprastante.
Di seguito sono riportate le immagini campionate dalle due griglie: quella a sinistra è stata
campionata dalla griglia nera, mentre quella a destra è stata campionata da quella grigia.

È possibile dunque notare la differenza tra le due immagini campionate


e l'efficienza della seconda griglia utilizzata (quella grigia).
Questo per quanto riguarda il campionamento spaziale, per quanto concerne invece
il campionamento temporale, un'immagine video in movimento è catturata prendendo “foto”
rettangolari del segnale ad intervalli di tempo periodici.
Riproducendo queste “foto” si ha un movimento apparente.
Un rapporto di campionamento temporale (detto anche “frame rate”) più alto dà un movimento
apparente più fluido nella scena video, ma richiede anche più campioni catturati e salvati.
Frame rate sotto i 10fps (frame per second) sono solitamente utilizzati per le comunicazioni video
a bassissimi bitrate, ma l'impressione di movimento è chiaramente innaturale.
Tra i 10 ed i 20 fps, l'immagine è un po' più fluida ma si notano sempre gli “scatti”.
Infine, per campionamenti a 25 o 30 fps si ha un'immagine abbastanza fluida,
sebbene sia possibile comunque notare gli “scatti” quando si ha un movimento rapido.
Quest'ultimi fps sono stati scelti come standard per le immagini televisive,
anche se solamente con frame rate di 50 o 60 fps si ha un movimento apparente fedele alla realtà.
Questo perché il video è solamente una serie di immagini riprodotte, ma l'occhio umano è in grado
di percepire molti più fps e, di conseguenza, noterà sempre un movimento “innaturale”
nelle immagini televisive con lo standard attuale.
Inoltre, un segnale può essere campionato come una serie di frame completi (campionamento
progressivo) o come una sequenza di field interlacciati (campionamento interlacciato).
In una sequenza video interlacciata, metà dei dati in un frame (un field)
è campionata ad ogni intervallo di campionamento temporale.
Un field è formato dalle linee pari o dispari all'interno di un frame video completo ed una sequenza
video interlacciata contiene una serie di field, ognuno rappresentante metà dell'informazione
di un frame video completo.
Il vantaggio di questo metodo è che è possibile mandare il doppio delle informazioni inviate in una
sequenza video progressiva con lo stesso data rate, dando una migliore impressione di movimento.
Ad esempio, una sequenza video PAL consiste in 50 field per second (25 righe pari e 25 righe
dispari) e, in fase di riproduzione, il movimento appare più fluido rispetto a quello della rispettiva
sequenza video a 25 fps.
Stessa cosa per l'NTSC che utilizza invece 60 field per second (30 righe pari e 30 righe dispari).
Ad ogni modo, mentre le televisioni a tubo catodico ed i pannelli ALiS plasma sono in grado di
riprodurre nativamente le sequenze video interlacciate, i moderni monitor per computer e le TV
basate sulla tecnologia LCD non lo sono.
Dunque, per poter riprodurre tali segnali, deve essere effettuato un processo di deinterlacciamento.
Il metodo di trasmissione interlacciata era stato inizialmente ideato infatti per le televisioni a tubo
catodico; il funzionamento alla base di tali televisioni è avere un fascio di elettroni che colpisce dei
fosfori. Ogni pixel, una volta colpito dal fascio, conserva l'energia per un certo periodo di tempo,
per poi spegnersi pian piano.
Dunque, se supponessimo di effettuare una scansione progressiva del quadro (lo schermo del
televisore), avremmo il fascio che investe, riga dopo riga, tutti i pixel a partire dal primo in alto a
sinistra, fino all'ultimo in basso a destra.
Ebbene, così facendo si andrebbero a creare fenomeni di sfarfallio in quanto non appena l'ultimo
pixel in basso a destra è investito dal fascio di elettroni (e si accende), il primo pixel in alto a
sinistra ha ormai consumato parte dell'energia acquisita ed è prossimo a spegnersi.
Per evitare tale sfarfallio e per l'adozione della tecnica del refresh rate di pari passo con la frequenza
della corrente, venne utilizzato il metodo di trasmissione interlacciato come lo conosciamo noi oggi.
La scansione del quadro viene quindi fatta in due passi: il primo passo illumina tutti i pixel,
da in alto a sinistra ad in basso a destra, delle righe dispari,
mentre il secondo effettua la stessa cosa ma con i pixel contenuti nelle righe pari.
Top Field

Bottom Field
Molteplici applicazioni video digitali hanno l'esigenza di consentire la riproduzione di video a
colori e quindi necessitano di un meccanismo di cattura e rappresentazione dell'informazione
del colore.
Un'immagine monocromatica richiede solamente un valore per indicare il luma di ogni campione
spaziale. Le immagini a colori invece richiedono almeno tre valori per pixel per rappresentare
adeguatamente il colore.
Il metodo scelto per la rappresentazione del luma e del chroma è detto “spazio di colore”.
Il più conosciuto spazio di colore è l'RGB, nel quale il campione dell'immagine a colori
è rappresentato da tre valori che indicano le relative proporzioni di Red, Green, Blue
(Rosso, Verde, Blu), i tre colori primari additivi.
Qualsiasi altro colore può essere creato dalla combinazione di rosso, verde e blu,
variandone le proporzioni.
Lo spazio di colore RGB è un ottimo spazio per la cattura delle immagini a colori e, per poterlo
utilizzare, è necessario catturare l'immagine filtrando le componenti rosso, verde e blu della scena,
catturandole ciascuna con una matrice di sensori separata.
Le televisioni a tubo catodico e quelle a cristalli liquidi rappresentano le immagini RGB
illuminando separatamente le componenti di rosso, verde e blu di ogni pixel secondo l'intensità
di ogni componente e, da una distanza non eccessivamente corta, i componenti separati sono visti
come “unificati” e danno l'impressione del colore.
Come già detto precedentemente per la codifica delle immagini fisse,
l'occhio umano è meno sensibile al chroma (colore) rispetto che al luma (luminanza).
Nello spazio di colore RGB, i tre colori sono egualmente importanti e sono solitamente salvati alla
stessa risoluzione, ma è possibile rappresentare il colore di un'immagine in maniera più efficiente
separando le informazioni del luma da quelle del chroma e rappresentando il luma con una
risoluzione maggiore rispetto al chroma.
Lo spazio di colore YcbCr e le sue varianti (YUV) è il metodo più utilizzato
per la rappresentazione delle immagini a colori.
“Y” rappresenta la componente di luma e può essere calcolato come il peso medio di rosso, verde
e blu (RGB):

dove k sono i fattori di peso.


Le informazioni di colore possono essere rappresentate come differenza di colore,
dove ogni componente di chroma è la differenza tra rosso, verde o blu (RGB) ed il luma (Y):

La descrizione completa di un'immagine a colori è data da Y (componente di luma) e dalle tre


differenze di colore Cb, Cr e Cg che rappresentano la differenza tra l'intensità di colore
ed il luma medio di ogni campione dell'immagine.
A primo impatto potrebbe sembrare strano poiché, mentre l'RGB aveva solo le tre componenti Red,
Green e Blue, adesso abbiamo quattro componenti, ovvero una in più.
Ebbene, Cb + Cr + Cg è una costante e quindi solamente due delle tre componenti di chroma
devono essere salvate o trasmesse, visto che la terza componente può sempre essere calcolata
dalle altre due.
Nello spazio di colore YcbCr, solo le componenti di luma (Y) e quelle di chroma blu e rosso
(Cb, Cr) sono trasmesse.
YcbCr ha un vantaggio significativo rispetto all'RGB ed è che le componenti Cr e Cb possono
essere rappresentate con una risoluzione minore rispetto ad Y proprio perché, come ho detto più
volte prima, l'occhio umano è meno sensibile al chroma rispetto che al luma.
Questo riduce la quantità di dati richiesta per rappresentare le componenti di chroma
senza avere un impatto significativo sulla qualità visiva (ovvero quella percepita).
Un'immagine nativa in RGB può inoltre essere convertita in YcbCr in modo da ridurne il peso
o i requisiti di trasmissione.
Prima di riprodurre l'immagine, di solito è necessario però convertirla di nuovo in RGB.
Le equazioni per convertire un'immagine RGB in YCbCr e viceversa, sono le seguenti:

È possibile notare che non c'è bisogno di specificare un fattore separato kg perché abbiamo che kb
+ kr + kg = 1 e che G può essere ricavato dalla rappresentazione YcbCr sottraendo Cr e Cb da Y,
dimostrando così che non è necessario salvare o trasmettere la componente Cg.
Le tre matrici di colore più utilizzate sono la BT.601 (utilizzata per le definizioni standard), la
BT.709 (utilizzata per le alte definizioni) e la nuova BT.2020 (utilizzata per le altissime definizioni).
Supponendo di dover convertire da YCbCr e RGB un video con la matrice BT.601, avremo,
secondo l'ITU-R, Kb = 0.114 e Kr = 0.299

Attualmente, l'H264 è in grado di supportare diversi tipi di campionamento per lo spazio di colore
YCbCr, ovvero il 4:2:0 (yv12 per l'8bit), il 4:2:2 (yv16 per l'8bit) ed il 4:4:4 (yv24 per l'8bit).
4:4:4 significa che le tre componenti Y, Cb e Cr hanno la stessa risoluzione e quindi esiste un
campione di ogni componente ad ogni posizione di pixel.
I numeri indicano il rapporto di campionamento di ogni componente nella direzione orizzontale:
per ogni campione di luma ci sono 4 campioni Cb e 4 campioni Cr.
È possibile quindi capire che il campionamento 4:4:4 preserva la completa fedeltà
delle componenti di chroma.
Nel campionamento 4:2:2, i componenti di chroma hanno la stessa risoluzione verticale di quelli del
luma, ma metà risoluzione orizzontale.
I numeri 4:2:2, infatti, significano che per ogni 4 campioni di luma nella direzione orizzontale,
ci sono due campioni Cb e due campioni Cr.
Il 4:2:2 è utilizzato per la riproduzione ad alta qualità ed è spesso utilizzato per i file inviati tra gli
studi di produzione, ma il più popolare è il 4:2:0.
Nel 4:2:0 (detto anche YV12), Cb e Cr (chroma) hanno metà risoluzione orizzontale
e metà risoluzione verticale di Y (luma).
Il termine “4:2:0” potrebbe portare confusione in quanto i numeri non hanno alcun riferimento
preciso e sembra sia stato deciso di chiamarlo in questa maniera per motivi storici,
oltre che per differenziarlo dal 4:4:4 e dal 4:2:2.
Il 4:2:0 è utilizzato comunemente per le applicazioni di tipo consumer come le video conferenze,
la televisione digitale ed i DVD.
Siccome ogni componente di colore contiene un quarto del numero di campioni della componente
di luma (Y), i video in 4:2:0 YCbCr richiedono esattamente la metà dei campioni richiesti
per il 4:4:4 e per l'RGB.
Ad esempio, supponiamo di avere una source a 720x576.
La risoluzione del luma Y è di 720x576 campioni, ognuno rappresentato con 8 bit.
Per quanto riguarda il chroma, abbiamo il campionamento 4:4:4 nel quale la risoluzione di Cb e Cr
è di 720x576 campioni, ognuno rappresentato con 8 bit, per un numero di bit totale dato da
720x576x8x3 = 9'953'280 bit.
Abbiamo poi invece il campionamento 4:2:0 nel quale la risoluzione di Cb e Cr è di 360x288
campioni, ognuno rappresentato con 8 bit, per un numero di bit totale dato da
(720x576x8) + (360x288x8x2) = 4'976'640 bit.
È dimostrato, quindi, che il campionamento 4:2:0 richiede metà bit della rappresentazione in 4:4:4.
Il campionamento 4:2:0 è chiamato anche “12 bpp” (12 bit per pixel).
Il motivo è di chiara interpretazione se esaminiamo il gruppo di quattro pixel
rappresentato nella figura soprastante (il quadrato).
Utilizzando il campionamento 4:4:4, sono richiesti 12 campioni, 4 per Y, 4 per Cb e 4 per Cr,
con un totale di 12x8 = 96 bit, una media di 96/4 = 24 bpp (24 bit per pixel).
Utilizzando il campionamento 4:2:0, sono richiesti solamente 6 campioni, 4 per Y, 1 per Cb
ed 1 per Cr, richiedendo un totale di 6x8 = 48 bit, una media di 48/4 = 12 bpp (bit per pixel).
In una sequenza video interlacciata con campionamento 4:2:0, i campioni di luma (Y) e chroma
(Cb e Cr) corrispondenti ad un frame video completo sono allocati in due field e l'H.264
utilizza il metodo riportato dalla figura sottostante: il numero totale di campioni in una coppia di
field è lo stesso del numero di campioni nel frame progressivo equivalente.

Dunque, dopo aver esplicato i diversi tipi di campionamento, tornando alla matrice di colore
BT.601 – utilizzata per i segnali video per la produzione televisiva – è curioso sapere che la
componente di luma di un segnale video è campionata a 13.5 Mhz e che la componente di chroma
è campionata a 6.75 Mhz per produrre un segnale YCbCr 4:2:2.
I parametri del segnale digitale campionato dipendono dal frame rate del video (30 Hz per un
segnale NTSC e 25 Hz per un segnale PAL).
NTSC:
Frame rate: 30 Hz
Field al secondo: 60
Linee per frame completo: 525
Campioni di luma per linea: 858
Campioni di chroma per linea: 429
Bit per campione: 8
Bitrate totale: 216 Mbps
Linee attive per frame: 480
Campioni attivi per linea (luma Y): 720

PAL:
Frame rate: 25 Hz
Field al secondo: 50
Linee per frame completo: 625
Campioni di luma per linea: 864
Campioni di chroma per linea: 432
Bit per campione: 8
Bitrate totale: 216 Mbps
Linee attive per frame: 576
Campioni attivi per linea (luma Y): 720

Il frame rate dell'NTSC (30 Hz) – che è più alto del 25Hz del PAL – è compensato da una
risoluzione spaziale più bassa in modo che il bitrate totale sia lo stesso in entrambi i casi: 216 Mbps.
È bene ricordare però che l'immagine rappresentata sul display è più piccola del numero totale in
quanto esclude gli intervalli orizzontali e verticali che esistono “fuori” dai bordi di ogni frame
e si definisce “area attiva” o “area di display”.
Inoltre, ogni campione ha un possibile range che va da 0 a 255 ed i livelli 0 e 255 sono riservati per
la sincronizzazione ed il segnale di luma “attivo” è ristretto ad un range che va da 16 (nero)
a 235 (bianco).
Negli standard di codifica video che tratterò più avanti,
farò utilizzo di termini quali il QCIF o l'SQCIF.
In pratica, di solito, si cattura o si converte un set di “formati di intermezzo” prima di encodare e
trasmettere ed il “Common Intermediate Format” (CIF) è alla base di numerosi set di formati.
L'immagine soprastante mostra la componente di luma di un frame video campionato in varie
risoluzioni, dal 4CIF al SQCIF (Sub-QCIF).
La scelta della risoluzione del frame dipende dalle applicazioni e dalle capacità di storage e
trasmissione: il 4CIF è appropriato per la televisioni a definizione standard e per i DVD, il CIF
ed il QCIF sono usati per le videoconferenze, ma il QCIF è utilizzato anche per le applicazioni
multimediali in ambito mobile, così come l'SQCIF, dove la risoluzione ed il bitrate sono limitati.

3) Utilizzo delle Trasformate nei codec di codifica video


Dopo aver introdotto le trasformate più utilizzate, la tesi si è sviluppata analizzando la loro
implementazione nella codifica delle immagini fisse,
prendendo in esame gli standard più utilizzati (sia lossless che lossy).
In questa terza parte, procederò nell'illustrazione della codifica tramite trasformata nei video,
partendo dall'H.261, descrivendo l'MPEG-1, illustrando l'MPEG-2,
argomentando sull'H.263, ponendo particolare attenzione sull'H.264, vertendo sull'H.265
ed analizzando in modo dettagliato il nuovo codec H.266 VVC.
Prima di trattare direttamente i codec ed esaminarli singolarmente,
è bene esplicare le loro funzionalità comuni ed i loro obiettivi.

– Generalizzazione su encoder e decoder

Un codec video ha l'obiettivo di encodare un'immagine o una sequenza video in forma compressa e
decodificarlo per produrre una copia esatta (lossless) o approssimativa (lossy) della sequenza video.
Un codec video rappresenta la sequenza video originale con un “modello”,
ovvero una rappresentazione codificata che può essere utilizzata per ricostruire il dato a video,
esattamente come già detto per la codifica delle immagini.
L'encoder video è fatto da tre unità funzionali principali: il modello temporale, il modello spaziale
e l'encoder entropico.
L'input al modello temporale è una sequenza video non compressa.
Il modello temporale cerca di ridurre la ridondanza spaziale sfruttando le similitudini tra i frame
video vicini, generalmente costruendo una predizione del frame corrente.
In alcuni standard, inoltre, la predizione è formata da uno o più frame precedenti e futuri
ed è migliorata dalla compensazione per differenze tra frame (predizione moto-compensata).
L'output del modello temporale è un frame residuo creato sottraendo la predizione dal frame
corrente ed un set di parametri di “modello”, di solito un set di vettori movimento
che descrivono come è stato compensato il movimento.
Il frame residuo forma l'input al modello spaziale che fa uso delle similitudini tra i campioni vicini
nel frame residuo per ridurre la ridondanza spaziale ed, in alcuni standard, tale processo viene
effettuato proprio applicando una trasformata ai campioni residui e quantizzando i risultati.
La trasformata converte i campioni in un altro dominio in cui sono rappresentati come coefficienti
di trasformata. I coefficienti sono quantizzati per rimuovere i valori insignificanti,
lasciando un piccolo numero di coefficienti significativi che garantiscono una rappresentazione
del frame residuo.
L'output del modello spaziale è un set di coefficienti di trasformata quantizzati.
I parametri del modello temporale (di solito vettori movimento)
ed i coefficienti del modello spaziale sono compressi dall'encoder entropico.
Quest'ultimo rimuove la ridondanza statistica nei dati (ad esempio, rappresentando i vettori
ed i coefficienti che occorrono più comunemente con dei codici binari corti)
e produce un bit-stream compresso o un file che può essere trasmesso o salvato.
Una sequenza compressa consiste in parametri di vettori movimento codificati,
coefficienti residui codificati e le informazioni dell'header.
Il decoder video, invece, ricostruisce i frame compressi del bit-stream.
I coefficienti ed i vettori movimento sono decodificati da un decoder entropico,
dopodiché il modello spaziale è decodificato per ricostruire una versione del frame residuo.
Il decoder utilizza i parametri dei vettori movimento (assieme ad uno o più frame decodificati
precedentemente) per creare una predizione del frame corrente
ed il frame stesso è ricostruito aggiungendo frame residui a tale predizione.

– 3.1) H.261

L'H.261 fu il primo standard di codifica video internazionale con un'adozione di mercato rilevante.
Per raggiungere un'alta efficienza di compressibilità, le soluzioni di codifica video devono sfruttare
la ridondanza spaziale (tipicamente utilizzando una trasformata), la ridondanza temporale
(tipicamente facendo alcune predizioni nel tempo) e la ridondanza statistica
(tipicamente tramite la codifica entropica).
Questo darebbe come risultato una codifica video lossless, tuttavia, dato che le soluzioni di codifica
video lossless non raggiungono un rapporto di compressione adeguato, le soluzioni di codifica
video sfruttano l'importanza degli elementi a livello percettivo per eliminare, tramite
quantizzazione, tutte le informazioni che non sono visivamente rilevanti, in modo da ricreare una
qualità visivamente simile all'originale, ma – di fatto – diversa.
Se sono necessari alti fattori di compressione, l'encoder può decidere di eliminare anche le
informazioni rilevanti a livello visivo, comportando una riduzione della qualità originale,
ma cercando comunque di preservare quanta più “qualità percepita” possibile.
L'unità base per la codifica video per l'H.261 sono i macroblocchi; ogni macroblocco
corrisponde a sample (campioni) di luma da 16x16 e ci sono due modi per encodare tali blocchi:

– Codifica Intra
Questi macroblocchi sono codificati utilizzando la stessa tecnica analizzata precedentemente
quando ho trattato il JPEG. In questo caso, non è sfruttata la ridondanza spaziale. La
codifica Intra è spesso utilizzata per il primo frame, per il frame successivo ad un cambio
scena ed anche per i macroblocchi corrispondenti agli oggetti che compaiono per la prima
volta in una scena, catalogati dunque come “nuovi”.
Il macroblocco è diviso in blocchi da 8x8 che sono trasformati utilizzando la DCT
bidimensionale ed i coefficienti risultanti dalla DCT sono poi quantizzati.
Infine, tutti i coefficienti quantizzati sono ordinati in una sequenza monodimensionale a “zig
zag”. Ogni coefficiente è rappresentato utilizzando un simbolo bidimensionale (run, level),
dove sono indicate la sua posizione e la sua quantizzazione. Poi, per poter sfruttare la
ridondanza statica, tali simboli vengono codificati con la codifica di Huffman.
– Codifica Inter
Con questa codifica, è possibile utilizzare le informazioni dei frame precedenti per encodare
il frame corrente, sfruttando la ridondanza spaziale tra i frame vicini.
Inoltre, questa modalità di codifica è anche in grado di individuare, stimare e compensare il
movimento in una sequenza, sfruttando la predizione temporale.
L'esempio che sto per proporre deve essere visto come anticipazione dell'MPEG-1, di cui
parlerò più avanti, ma comunque valido per capire concettualmente la motocompensazione
ed ho ritenuto opportuno parlarne ora per un fatto di integrità relativa alla codifica inter.
Supponiamo dunque di avere una rappresentazione di un paesaggio (pensiamo ad una
videoconferenza in cui, come introduzione, si mostra il paesaggio visto dalla finestra) e
supponiamo di avere una ripresa che si muove da sinistra verso destra.

Prendiamo adesso un punto di riferimento: il faro.


Com'è logico pensare avremo i frame iniziali che contengono solo il mare ed il paesaggio, i
frame successivi che conterranno il faro (che “entra” da destra) e quelli seguenti che
vedranno “uscire” il faro (da sinistra).
Ripetere tutte le informazioni relative ai blocchi del faro sarebbe inutile quanto dispendioso
in termini di compressione leggera, quindi, tali informazioni, vengono semplicemente
ripetute “spostando” i blocchi di riferimento.
Dunque, per eseguire la stima del movimento, il macroblocco corrente è comparato coi
macroblocchi vicini del macroblocco corrispondente nel frame precedente.
Se viene individuato il movimento, le due direzioni (orizzontale e verticale) vengono salvate
in due interi chiamati “componenti del vettore di movimento” ed i vettori di movimento
vengono poi sottoposti alla codifica entropica.
La differenza tra il macroblocco corrente ed il macroblocco predetto è computata eseguendo
quella che si chiama “motocompensazione”.
Se invece non viene individuato movimento, la differenza è considerata “errore di
predizione” ed è computata tra il macroblocco corrente ed il macroblocco corrispondente
nel frame precedente.
Queste differenze (che dovrebbero essere il più piccole possibile) sono poi trasformate,
quantizzate e sottoposte a codifica entropica.
È doveroso però ricordare che anche se la moto-compensazione rappresenta un grandissimo
vantaggio in termini di compressione, è anche vero che il calcolo computazionale richiesto
per eseguirla è incredibilmente alto, sia in encoding che in decoding.
Questo perché in fase di encoding dev'essere effettuata la ricerca sui blocchi del frame
precedente, mentre in fase di decoding, il decoder dovrà effettuare uno “spostamento”.
Ultima nota di colore è che il processo di predizione può essere modificato dal “loop filter”
(LF) che può essere “on” o “off” per aumentare la qualità dell'immagine rimuovendo il noise
ad alta frequenza quando necessario.

– Trasformata
La trasformata utilizzata dall'H.261 è molto simile a quella utilizzata nel JPEG:
è una DCT bidimensionale separabile di grandezza 8x8.
Prima di eseguire la trasformata, il range dei dati è impostato in modo da essere centrato su
zero; questo significa che è effettuata una sottrazione di 128 ai sample nel range 0-255 per i
sample a 8bit.

– Quantizzazione
L'H.261 può utilizzare come passi di quantizzazione tutti i valori pari che vanno da 2 a 62.
All'interno di ogni macroblocco, tutti i coefficienti DCT sono quantizzati con lo stesso passo
di quantizzazione ad eccezione dei coefficienti DC per i macroblocchi intra che sono sempre
quantizzati con il passo 8 a causa della loro critica importanza visiva.
Ovviamente, più il valore del passo di quantizzazione è alto, più la quantizzazione sarà
marcata, più il valore sarà basso, più la quantizzazione sarà minore.
Tramite il processo di quantizzazione, dunque, come accadeva nella codifica delle immagini
fisse, vengono tagliati i valori di importanza visiva minore per passare a quelli di importanza
maggiore. Un passo di quantizzazione 10 (ad esempio) sarà molto più vicino alla qualità
percepita da una codifica lossless di quanto non lo sia un passo a 50.
È bene ricordare ancora una volta che sebbene la quantizzazione cerchi di tagliare fattori di
minore importanza visiva, se il passo è molto alto (e quindi si desidera una grande
compressione), si vanno a tagliare parti importanti di informazione
a livello di percezione visiva.
Ad ogni modo, anche se si ha una perdita di qualità, questo viene fatto nel modo più
“leggero” possibile, proprio perché si cerca di tagliare sempre quelli meno rilevanti.
Alcune parti considerate dunque “meno rilevanti” da un passo a 50,
potrebbero invece essere considerate “rilevanti” da un passo a 10 e così via.

– Informazioni aggiuntive e valutazioni finali


L'H.261 opera a bitrate tra 40kbit/s e 2 Mbit/s e supporta risoluzioni spaziali QCIF (176x144
pixel) e, volendo, CIF (352x288 pixel) ad un sotto-campionamento 4:2:0 (ogni chroma è
sottoposto a sotto-campionamento da un fattore di 2, sia orizzontalmente che verticalmente).
L'algoritmo di codifica opera su contenuti progressivi a 30 fps (frame per second, immagini
al secondo), ma questo frame rate può essere ridotto saltando 1, 2 o 3 frame ogni volta che
ne è trasmesso uno.
È doveroso ricordare che l'H.261 era stato ideato per la videotelefonia
e per le videoconferenze tramite linee telefoniche ISND (Integrated Service Digital
Network) che hanno tipicamente bitrate multipli di 64 kbit/s.
Proprio a causa delle applicazioni per cui è stato pensato, l'H.261 ha dei critici requisiti di
ritardo, in modo da consentire una normale conversazione bidirezionale.
D'altra parte, i suoi requisiti di qualità non sono poi tanto critici, visto che, in questo caso,
una qualità medio-bassa potrebbe essere sufficiente per le comunicazioni personali.
Come primo standard di codifica, l'H.261 non ha nessun altro standard precedente a cui
poter essere comparato, ad ogni modo, è possibile valutare le sue performance a seconda dal
bitrate disponibile, dalle caratteristiche delle sequenze video e, più che altro, dall'encoding.

Prendiamo per esempio la figura soprastante che raffigura la qualità dell'immagine


(utilizzando la metrica di qualità PSNR), contro il bitrate per la nota sequenza video-
telefonica “Miss America” a risoluzione QCIF.
Il diagramma rappresenta i risultati per la sequenza codificata a 30 fps e 10 fps.
Inoltre, sono rappresentati i risultati con e senza i vettori di movimento e con e senza i filtri
di loop a bassa frequenza quando sono utilizzati i vettori movimento (+MV +LF).
Osservando il grafico è chiaro che la qualità dell'immagine dipende principalmente
dal bitrate disponibile.
Come previsto, a bitrate più bassi, il PSNR medio è più basso che per gli alti bitrate.
Per alcuni bitrate, la sequenza video a 10 fps ha, di media, più bit per frame rispetto alla
sequenza video a 30 fps.
Non solo, il PSNR medio per la sequenza video con il frame rate più basso
è tipicamente più alta, sebbene l'impressione del movimento possa non essere buona
se la sequenza è particolarmente in movimento (è doveroso ricordare che l'occhio umano è
in grado di percepire fino a 55 fps).
Nel grafico soprastante è raffigurata la variazione del PSNR contro il rapporto di
compressione nella stessa sequenza video.
All'aumentare del rapporto di compressione, il numero di bit disponibile per rappresentare la
sequenza video diminuisce; questo risulta in una riduzione del valore medio del PSNR
ed una conseguente riduzione della qualità dell'immagine.
Analizzando entrambi i grafici è possibile concludere che l'introduzione della moto-
compensazione ed il loop filter (LF) aumentano sempre la qualità della sequenza video
ricostruita per tutti i bitrate ed i rapporti di compressione; ovviamente, però, bisogna tenere
conto che si ha un aumento del costo computazionale.
I benefici, inoltre, sono molto più visibili ai bassi bitrate ed agli alti rapporti di
compressione.

– 3.2) Video Standard, MPEG-1

Lo standard video MPEG-1 era il primo standard di codifica video definito dall'MPEG.
L'obiettivo principale dello standard di codifica MPEG-1 era di comprimere in modo efficiente le
informazioni audiovisive per il video storage, in particolare per salvare digitalmente la qualità
visiva delle sequenze delle VHS nei Compact Disk (CD).
Inoltre, lo standard MPEG-1 definisce i codec video ed audio nelle sue parti video ed audio
associate.
Per il video dell'MPEG-1, il bitrate finale si aggira intorno a 1.2 Mbit/s per comprimere risoluzioni
CIF di video a 25 Hz.
A differenza dell'H.261, l'MPEG-1 video non ha requisiti critici per il “real-time”,
visto che l'obiettivo principale non sono applicazioni in tempo reale.
Ad ogni modo, ha altri “requisiti critici” relativi al video storage, come gli accessi random,
per provvedere alle funzionalità di storage tipiche, tipo il fast forward ed il reverse playback.
Questo standard venne originariamente ottimizzato per il SIF, che ha una risoluzione di 352x288
pixel a 25 Hz e 325x240 a 30 Hz con un sotto-campionamento 4:2:0.
Oltre ai metodi di predizione utilizzati dall'H.261 – dove un macroblocco può essere predetto da un
macroblocco del frame precedende (predizione in avanti), l'MPEG-1 può adottare una predizione
“all'indietro”, basata sul principio che i macroblocchi possono essere predetti anche prendendo
come riferimento i macroblocchi dei frame futuri.
Questo tipo di predizione temporale ha il suo costo, specialmente in termini di ritardo di codifica e
di complessità, che possono essere accettabili, considerando che le applicazioni in real-time non
sono l'obiettivo principale di questo standard e che la codifica “offline” è il campo più utilizzato.
A causa delle strutture di memorizzazione richieste sopraelencate,
l'MPEG-1 definisce tre tipi di frame dipendenti dai tool di codifica utilizzati:

– Intra-frame (I-frame):
I frame Intra includono solamente i macroblocchi codificati in intra.
Questi frame sono principalmente utilizzati per provvedere accessi random dato che non
dipendono da altri frame.
Prevengono inoltre la propagazione d'errore associata alla derivazione, dato che gli altri tipi
di frame dipendono da questi e quindi potrebbero potenzialmente propagare l'errore nei
frame successivi!

– Inter-frame (P e B):
I frame inter potrebbero includere macroblocchi codificati intra e si dividono in due: P
(parzialmente predetti) e B (totalmente predetti).
Prima ho parlato di predizione “in avanti” e predizione “all'indietro”; ebbene, i fotogrammi
P utilizzano solo la predizione “in avanti”, mentre i fotogrammi B possono utilizzarle
entrambe. In particolare, negli “Inter P-frame”, i macroblocchi codificati in inter possono
essere predetti solo dai frame I precedenti (o dagli stessi fotogrammi P precedenti),
da cui “predizione in avanti”.
Per quanto riguarda gli “Inter B-frame”, invece, i macroblocchi codificati in inter B possono
utilizzare la predizione “in avanti”, la predizione “indietro” oppure entrambe;
si ha così la “predizione bidirezionale”.
Come ho già detto, i fotogrammi B sono “totalmente predetti”, nel senso che possono
utilizzare solo i fotogrammi I e P e richiedono meno bit degli altri tipi di frame.
Ad ogni modo, se troppi frame B si susseguono, possono esserci dei problemi.
Questo per due motivi di base: il primo è che si avrà un ritardo nella codifica per il fatto che
i fotogrammi di referenza I e P saranno distanti, ed il secondo è che proprio perché sono
distanti, si avrà anche una maggiore possibilità di propagazione d'errore.

È comunque importante sottolineare che l'efficienza di compressione dei P-frame rispetto agli I-
frame e dei B-frame rispetto ai P-frame è strettamente relazionata alla complessità associata al
processo di stima del movimento (con un reference frame per i P e due reference frame per i B)
e il ritardo aggiuntivo per i B-frame.

Ho ritenuto opportuno servirmi della rappresentazione dell'architettura rappresenta nella figura


soprastante per spiegare come vengono trattati gli intra ed gli inter.

Per quanto riguarda i macroblocchi intra:

– DCT: Dopo aver diviso i macroblocchi in blocchi 8x8, i sample (campioni) vengono
trasformati utilizzando la Trasformata Discreta del Coseno Bidimensionale.

– Quantizzazione: Dopo il processo di trasformata, i coefficienti vengono quantizzati.

– Encoding Entropico: Infine, i coefficienti quantizzati della DCT sono encodati


entropicamente utilizzando la codifica di Huffman.

Per quanto riguarda i macroblocchi inter:

– Stima del movimento: I macroblocchi dei frame di predizione precedenti e futuri (I o P)


sono comparati al macroblocco corrente.
Se questa operazione individua movimento, i vettori movimento sono encodati
entropicamente. L'MPEG-1 utilizza un'accuratezza della stima di movimento di mezzo pixel
per consentire una stima più precisa del movimento con una conseguente riduzione
dell'errore di predizione.

– Invio delle differenze: Se viene individuato movimento, le differenze sono codificate


utilizzando la moto-compensazione, altrimenti, avviene una semplice predizione dal frame
di predizione rilevante corrispondente al macroblocco. Queste differenze, vengono poi
trasformate, quantizzate ed encodate entropicamente.

Anticipo inoltre che, visto che lo standard è valido anche per gli altri codec di cui parlerò più avanti,
non lo ripeterò ogni volta.

– Trasformata e Quantizzazione

Per quanto riguarda il processo di quantizzazione utilizzato nell'MPEG-1,


posso dire che è simile a quello utilizzato dal JPEG.
Il passo di quantizzazione può essere differente per ogni coefficiente della DCT
ed è definito con le matrici di quantizzazione.
Ci sono due matrici di quantizzazione standard di base: una per gli intra ed una per gli inter.
Per quanto riguarda gli inter, i coefficienti alle alte frequenze non sono necessariamente associati ai
contenuti ad alta frequenza dato che possono risultare da un'immagine povera
o dal noise introdotto dalla cinepresa; in questo caso, i passi di quantizzazione sono constanti.
Per gli intra, la quantizzazione tiene conto della sensibilità visiva delle varie frequenze spaziali
e le matrici di quantizzazione possono cambiare per ottenere una migliore efficienza di codifica.
Esattamente come l'H.261, i coefficienti DC dei macroblocchi codificati in intra
sono sempre quantizzati con il passo 8.

Nell'MPEG-1 i coefficienti DC sono codificati differentemente in ogni macroblocco


e tra macroblocchi vicini; tale approccio è stato scelto proprio per sfruttare le similitudini
tra i coefficianti DC dei blocchi adiacenti.

– Informazioni aggiuntive e valutazioni finali

Comparato all'H.261, l'MPEG-1 è molto migliore in termini di efficienza di compressione,


grazie alle innovazioni introdotte a livello tecnico.
Un esempio è la possibilità di avere predizioni bidirezionali ed anche l'accuratezza del movimento
di metà pixel, tuttavia, ovviamente, questo ha portato ad un aumento della complessità
e del costo computazionale.
Ad ogni modo, dato che stiamo parlando del video storage e non del “real-time” (come accadeva
per l'H.261), tale costo è perfettamente tollerabile, soprattutto se si pensa al fatto che lo scopo
principale dell'MPEG-1 è di ottenere la maggior compressione possibile per il video storage.
Per le sequenze meno compresse e con meno bitrate, l'H.261 raggiunge in genere rapporti di
compressione migliori dell'MPEG-1 (a pari qualità),
visto che l'MPEG-1 è ottimizzato per bitrate di 1.2 Mbit/s.
Inoltre, le videoconferenze e la videotelefonia presentano in genere poco movimento,
bitrate più bassi e richiedono una bassa complessità ed un basso costo computazionale
a causa del “real-time”, dunque, in questo caso,
l'H.261 potrebbe ancora essere la scelta migliore rispetto all'MPEG-1.
Ad ogni modo, per contenuti video generali tipo i film,
l'MPEG-1 presenta significativi vantaggi in termini di efficienza di compressione.

– 3.3) Video Standard, MPEG-2

L'MPEG-2 fu il primo standard creato sia per il broadcast che per lo storage e venne ideato
per codificare sequenze video ad alta qualità e risoluzione senza una visibile perdita di qualità, ed
aveva i seguenti target (obiettivi):

– Distribuzione Secondaria: per il broadcast, il segnale da 3-5 Mbit/s dev'essere migliore


o simile alla qualità dei sistemi analoghi disponibili dell'epoca coi quali venivano lavorati
e trasmessi materiali in PAL, SECAM ed NTSC.

– Distribuzione Primaria: per le pubblicazioni interne (ad esempio le trasmissioni tra gli
studi), la qualità del segnale ad 8-10 Mbit/s dev'essere simile alla qualità originale,
ovvero simile alla rappresentazione della raw di partenza.

L'MPEG-2 basa il suo utilizzo principale sulle trasmissioni video digitali come il via cavo,
il satellitare ed il digitale terrestre, così come il Digital Video Disk storage,
più comunemente noto come DVD.
Inizialmente, l'MPEG-2 era pensato per coprire la codifica video fino a 10 Mbit/s,
lasciando gli alti bitrate e le alte risoluzioni spaziali ad un altro codec video, l'MPEG-3.
Ad ogni modo, l'MPEG-3 non venne mai definito come standard,
visto che l'MPEG-2 si dimostrò in grado di poter gestire anche l'HD.
A differenza dei precedenti standard già analizzati sopra, l'MPEG-2 è capace di codificare contenuti
video interlacciati, così come quelli progressivi e questo tornò essere molto utile
in quanto le trasmissioni televisive fanno uso di contenuti interlacciati.
Un'altra caratteristica introdotta da questo standard è la scalabilità (fedeltà temporale e spaziale)
e tale funzione può essere molto utile per poter trasmettere in network eterogenei
e con vari tipi di terminali quali, ad esempio, i canali a risoluzione standard ed HD.
Proprio a causa degli ampi e vari campi di utilizzo dell'MPEG-2, le sue impostazioni
(ed i suoi standard) sono stati definiti in termini di “profile” e “level”.
Il “profile” definisce un sottoinsieme dei tool di codifica e della sintassi di bitstream,
provvedendo una varietà di caratteristiche richieste da alcune applicazioni
con un certo livello di complessità, quali, ad esempio, la codifica interlacciata, i B-Frame
e la scalabilità.
All'interno di ogni profile, il level definisce il limite del range dei parametri operativi,
quali la risoluzione spaziale (da 352x288 a 1920x1152) ed il bitrate (da 4 Mbit/s ad 80 Mbit/s).

– Architettura
I tool di codifica utilizzati dall'MPEG-2 sono molto simili a quelli utilizzati dall'MPEG-1;
le due differenze sostanziali sono legate alle due principali caratteristiche innovative dell'MPEG-2:
la codifica interlacciata e la codifica scalabile.
Quest'ultima caratteristica è importante in quanto offre una scalabilità temporale (cambio del frame
rate), una scalabilità spaziale (cambio di risoluzione)
ed una scalabilità di fedeltà (cambio della qualità).
Di seguito, viene rappresentata l'architettura dell'MPEG-2 senza la codifica scalabile.

È importante ricordare che la scalabilità temporale era già stata introdotta con l'MPEG-1,
in quanto effettuata già dalla semplice struttura di predizione temporale basata sui tipi I, P e B
già analizzati precedentemente, il che significa che le novità della codifica scalabile
introdotte nell'MPEG-2 riguardano la risoluzione spaziale e la scalabilità della qualità.

– Trasformata

Lo standard video MPEG-2 utilizza sempre la stessa Trasformata Discreta del Coseno
bidimensionale utilizzata dall'MPEG-1.
Per quanto riguarda la possibilità di effettuare la codifica di sequenze video interlacciate,
è stata introdotta la possibilità di utilizzare un diverso ordine di scansione, appositamente per esse.

Con questo diverso ordine di scansione, i coefficienti DCT corrispondenti alle transizioni verticali
sono privilegiati (in termini di ordine di scansione),
dato che la correlazione verticale è ridotta per le immagini interlacciate con più movimento.
– Quantizzazione
Per quanto riguarda la quantizzazione, l'MPEG-2 utilizza la stessa tecnica di quantizzazione
utilizzata dall'MPEG-1, facendo uso delle matrici di quantizzazione presentate precedentemente e,
ancora una volta, i coefficienti DC dei macroblocchi codificati intra sono quantizzati con passo 8.

– Valutazioni finali

A confronto con l'MPEG-1, è chiaro che l'MPEG-2 possa produrre una qualità video migliore
per video interlacciati a prescindere dalla quantità di movimento presente, tuttavia,
per i video progressivi e per i bitrate attorno a 1.2 Mbit/s, l'MPEG-1 è superiore all'MPEG-2.
Questo perché l'MPEG-2 ha una struttura sintattica più complicata,
che può aumentare il peso delle informazioni a bassi bitrate.
Per gli alti bitrarte (ovvero dai 3.0 Mbit/s in su), invece, anche per i video progressivi,
l'MPEG-2 raggiunge qualità superiori rispetto all'MPEG-1 allo stesso bitrate,
visto che quest'ultimo non è ottimizzato per questo genere di bitrate, mentre l'MPEG-2
riesce ad ottenere ottime compressioni per video ad alte risoluzioni ed alta qualità.

3.4) Video Standard, H.263

Lo standard H.263 venne creato con l'intento di rimpiazzare l'H.261,


aumentando l'efficienza di compressione, soprattutto ai bassi bitrate.
La motivazione principale dietro alla creazione di questo standard era l'assenza di uno standard che
potesse garantire l'interoperatività tra i terminali digitali di video-telefonia
per gli analoghi network telefonici (PSTN) ed i mobile network emergenti.
Questo processo di standardizzazione doveva essere effettuato velocemente
per provvedere ad una veloce distribuzione dei prodotti del mercato.
Inoltre, l'H.263, è basato principalmente sulle tecnologie già pre-esistenti,
in particolar modo sull'H.261 e sull'MPEG-1.

– Architettura

Sebbene l'H.261 e l'H.263 condividano la stessa struttura di codifica di base,


presentano comunque alcune differenze, anche se, alcune di esse,
sono miglioramenti già introdotti nell'MPEG-1.
È possibile individuare 6 differenze sostanziali tra l'H.261 e l'H.263:

1) Target Bitrate – Il target bitrate dell'H.261 è px64 kbit/s (p=1, 2... 30) mentre l'H.263
punta a bitrate al di sotto dei 64 kbit/s per consentire la video-telefonia PSTN.

2) Formati di Immagine – Oltre ai formati già utilizzati dall'H.261 (ovvero il QCIF ed il CIF),
l'H.263 supporta i formati sub-QCIF, 4CIF ed il 16CIF.

3) Accuratezza di motocompensazione – Come lo standard MPEG-1,


l'H.263 supporta l'accuratezza fino a metà pixel.

4) Predizione dei vettori spostamento – I vettori spostamento sono codificati come nell'H.261,
ma, oltre ai macroblocchi precedenti, anche i macroblocchi nella riga di macroblocchi
precedente sono utilizzati per la predizione di vettori spostamento
e questo consente di ridurre l'errore nel bitstream.
5) Modalità PB-Frame – Un PB-Frame consiste in due immagini codificate come una unità.
Il frame di tipo P è predetto dall'ultimo frame P decodificato
ed il frame B è predetto sia dall'ultimo che dal corrente frame P.

6) VLC tables – L'H.263 utilizza triplette run, level, eob per codificare i coefficienti DCT
e non più le doppiette run, level per evitare di codificare esplicitamente il simbolo eob (End
of Block).

– Trasformata

Per quanto riguarda la trasformata, l'H.263 utilizza la stessa Trasformata Discreta del Coseno
bidimensionale utilizzata dall'H.261 e, come sempre, tale trasformata è applicata a blocchi di 8x8.

– Quantizzazione

Per quanto concerne la quantizzazione, l'H.263 utilizza lo stesso metodo descritto per l'H.261.
Lo stesso identico passo (valori pari contenuti tra 2 e 62) è utilizzato per tutti i coefficienti
nello stesso macroblocco, ad eccezione dei coefficienti DC dei macroblocchi codificati intra,
che sono quantizzati con passo 8.

– Valutazioni finali

Lo standard H.263 è superiore in termini di efficienza di compressione al precedente H.261


per qualsiasi bitrate, anche sopra ai 64 kbit/s.
Con una tale dimostrazione di efficienza, è possibile affermare che l'H.263 ha rimpiazzato
positivamente e completamente l'H.261 come standard di codifica video per le comunicazioni a
bassi bitrate; inoltre, la complessità dell'H.263 è solo appena più alta di quella dell'H.261.
3.5.0) Video Standard, MPEG-4

Prima di andare a parlare dell'MPEG-4, è bene chiarire a quale versione andrò a fare riferimento.
L'MPEG-4, ancora oggi, è in continua evoluzione ed è diviso in “part” (parti).
Spesso le compagnie che promuovono la compatibilità con tale video standard non forniscono alcun
dato sulla “part” dello standard a cui fanno riferimento, il che potrebbe creare un po' di confusione.
Le “part” più importanti e rilevanti, nonché quelle di cui parlerò in questa tesi sono la “part2” (che
include l'Advanced Simple Profile utilizzato da codec come il DviX e l'Xvid) e la “part 10” (ovvero
l'Advanced Video Coding AVC, meglio conosciuto come H.264, utilizzato dall'x264,
nonché standard di codifica ad alta risoluzione per i bluray).

3.5.1) Video Standard, MPEG-4 Visual (MPEG-4 part 2)

L'MPEG-4 Visual ha l'obiettivo di specificare i codec per vari tipi di oggetti visivi da utilizzare nel
contesto dello standard MPEG-4, che adotta per la prima volta un paradigma di rappresentazione
visiva basata sugli oggetti e non sui frame.
In questo contesto, lo standard MPEG-4 copre una vasta gamma di applicazioni come, ad esempio,
le telecamere di sorveglianza, le comunicazioni mobile, lo streaming in internet ed intranet,
le TV digitali, la post-produzione ecc.
Lo standard MPEG-4 Visual specifica codec per oggetti visivi naturali e sintetici;
in termini di codec video, specifica i codec per oggetti visivi rettangolari e di forma arbitraria.
Per gli oggetti rettangolari, la risoluzione spaziali va dal sub-QCIF a risoluzioni da studio
che si aggirano attorno ai 4k x 4k pixel.
Ovviamente, come considerato negli standard precedenti,
un frame è un caso particolare di oggetto video.

– Architettura

Lo Standard MPEG-4 Visual include strumenti per codificare video naturali ed immagini fisse
(textures visive) e questo consente di codificare scene che contengono immagini fisse
ed in movimento utilizzando lo stesso standard.
Ogni scena da codificare può essere composta da uno o più oggetti video.
Nella codifica basata sugli oggetti, i frame video sono definiti in termini di VOP (Video Object
Planes) ed ogni VOP è la rappresentazione video momentanea
di uno specifico oggetto di interesse da codificare o col quale interagire.
Ogni oggetto video è incapsulato in un rettangolo di selezione che è diviso poi in macroblocchi
da 16x16 pixel che possono essere classificati come trasparenti, opachi o di bordo.
I macroblocchi del rettangolo di selezione che sono completamente all'esterno del VOP
non hanno bisogno di essere codificati e vengono definiti “trasparenti”.
I macroblocchi del rettangolo di selezione che sono completamente all'interno del VOP
sono codificati inter o intra utilizzando la motocompensazione e l'encoding tramite DCT
e vengono definiti “opachi”.
I macroblocchi del rettangolo di selezione che sono in parte esterni ed in parte interni al VOP
sono processati con strumenti specifici atti alla codifica degli oggetti di forma arbitraria
e vengono definiti “di bordo”.
Per capire meglio le distinzione, i tre tipi di macroblocchi sono riportati nella figura sottostante:
Per quanto riguarda invece la codifica video rettangolare (o basata sui frame),
che è funzionalmente simile alla codifica basata sui frame precedentemente analizzata,
ci sono alcuni miglioramenti introdotti dall'MPEG-4 Visual,
soprattutto in termini di moto-compensazione.

– La moto-compensazione supporta vettori di movimento con una maggiore accuratezza,


soprattutto ad un quarto di pixel, consentendo migliori predizioni
e riducendo gli errori di predizione.

– Invece di utilizzare vettori di movimento locali per ogni macroblocco,


lo strumento di “Moto-compensazione Globale” consente di utilizzare
anche un vettore movimento per VOP (che potrebbe essere un frame).
Questo può tornare utile per sequenze con un'ampia porzione di movimento globale
traslazionale (come il camera panning) ed anche per il movimento non-traslazionale
(come lo zoom o la rotazione).

– La Direct Mode nella predizione bidirezionale è una generalizzazione dei PB-Frame


già introdotta nell'H.263; vengono utilizzate sia la predizione in avanti che quella
all'indietro, ma i vettori movimento richiesti sono derivati dai vettori movimento
dei macroblocchi collocati nel riferimento all'indietro
ed è trasmesso solo un termine di correzione chiamato “delta vector”.

Nella figura sottostante è riportata l'architettura di encoding di oggetti video rettangolari.


È inoltre doveroso ricordare che gli oggetti fissi, chiamati anche “visual textures”,
sono codificati mediante una soluzione basata sulla Trasformata di Wavelet,
simile a quella utilizzata dallo standard JPEG2000 precedentemente analizzato.
– Trasformata

L'MPEG-4 Visual utilizza anch'esso la Trasformata Discreta del Coseno bidimensionale


per trasformare i blocchi da 8x8 che compongono un macroblocco.

– Quantizzazione

L'MPEG-4 Visual ha la possibilità di quantizzare i coefficienti in due modi diversi:


il primo è derivato dall'MPEG-2 (metodo 1) ed il secondo dall'H.263 (metodo 2).
Per quanto riguarda il metodo 1, tale metodo prende in considerazione le propietà
del sistema visivo umano, consentendo un passo di quantizzazione diverso
per ogni coefficiente di trasformata per mezzo delle matrici di quantizzazione.
Di sotto sono riportate le matrici di quantizzazione di default per i macroblocchi codificati intra
(sinistra) e quelli codificati inter (destra).

Per quanto concerne invece il metodo 2, è meno complesso e più facile da implementare,
ma consente un solo valore di passo per macroblocco;
il che significa che l'intero macroblocco verrà processato con tale passo!
La selezione del metodo di quantizzazione è decisa dall'encoder
e tale decisione viene poi trasmessa al decoder.
Per i blocchi codificati intra,
il coefficiente DC è quantizzato usando un passo di quantizzazione prefissato.
Come già esplicato prima, l'MPEG-1 predice i valori dei coefficienti DC utilizzando i valori
dei coefficienti DC dei blocchi vicini.
Per alcuni coefficienti DC ed AC dei blocchi vicini ci sono alcune dipendenze statistiche
quali il fatto che il valore di un blocco può essere predetto dal valore corrispondente
di uno dei blocchi vicini.
Tale fatto è sfruttato dall'MPEG-4 ed è chiamato “predizione DC/AC”
e tale predizione è applicata solo in caso di macroblocchi codificati intra.
Per la scansione dei coefficienti DCT (che corrisponde ad una conversione da bidimensionale a
monodimensionale delle informazioni dei coefficienti DCT), ci sono due modalità di scansione
aggiuntive disponibili, oltre a quella a zig-zag utilizzata in molti standard,
quali la scansione alternata orizzontale e la scansione alternata verticale.

Per quanto riguarda i macroblocchi di bordo, questo standard supporta anche l'utilizzo
di una trasformata speciale chiamata “Shape-Adaptive DCT” ovvero “DCT a forma adattiva”.
In pratica, lo scopo di tale trasformata è di codificare solo i pixel opachi
all'interno dei macroblocchi di bordo che non sono completamente “riempiti” da dati di texture.

– Valutazioni Finali

L'obiettivo principale dell'MPEG-4 Visual non è quello di aumentare l'efficienza di compressione,


anche se, per alcuni dei suoi profili, in particolare per la codifica video basata sui frame,
ci sono alcuni benefici di compressione rispetto agli standard precedenti,
grazie ai nuovi strumenti di codifica.
Per gli alti bitrate (ovvero bitrate che vanno da 5 Mbit/s a 15 Mbit/s),
l'MPEG-2 ottiene già buoni risultati e, per tali range di bitrate,
l'MPEG-4 Visual non porta alcun beneficio significativo.
Ad ogni modo, per i bitrate medio-bassi (ovvero bitrate fino ad un massimo di 3 Mbit/s),
l'MPEG-2 non consente una buona compressione ed è addirittura superato dall'MPEG-1 (come
detto nel paragrafo precedente) ed è proprio in questo ambito che l'MPEG-4 Visual
sfodera il suo potenziale, ottenendo risultati di compressione migliori
in tutti i tipi di sequenza video.
Per i bitrate veramente bassi (ovvero circa 50 kbit/s), invece, l'H.263 è ancora superiore all'MPEG-4
Visual in quanto, per tali bitrate, quest'ultimo non utilizza tutti gli strumenti di codifica disponibili
ed utilizza il “Simple Profile” in modo da ridurre la complessità
ed il ritardo causato dal loro utilizzo.
Ad ogni modo, per bitrate medi (ovvero 1.5 Mbit/s), l'MPEG-4 Visual è superiore anche all'H.263,
in quanto può utilizzare l' “Advanced Simple Profile” che sfrutta tutti gli strumenti di codifica,
quali i B-frame, la motocompensazione per quarti di pixel,
il metodo di quantizzazione 1 basato sull'MPEG-2 e la motocompensazione globale.
3.5.2) Video Standard, MPEG-4 (Part 10), AVC H.264

Dopo aver analizzato l'MPEG-4 (Part 2) Visual, è doveroso esplicare l'MPEG-4 (Part 10),
ovvero l'MPEG-4 Advanced Video Coding H.264.
L'H.264 è lo standard attualmente più utilizzato, nonché alla base di servizi di streaming come
Vimeo, software web come Adobe Flash Player e Microsoft Silverligth ed anche per le trasmissioni
HDTV terrestri (ISDB-T, DVB-T, DVB-T2), via cavo (DVB-C) e satellitari (DVB-S, DVB-S2).
L'intento dell'H.264 era di creare uno standard in grado di fornire una buona qualità video a bitrate
più bassi degli standard precedenti (metà bitrate dell'MPEG-2, dell'H.263 o dell'MPEG-4 Part 2),
senza aumentare di tanto la complessità ed evitare di renderlo troppo esoso di risorse e, difatti,
inutilizzabile.
Un altro obiettivo era quello di garantire abbastanza flessibilità da consentire allo standard di essere
applicato ad una vasta gamma di applicativi su un ampio raggio di network e sistemi,
che variano da bitrate molto bassi a bitrate molto alti, da risoluzioni molto basse
a risoluzioni molto alte, dal broadcasting, allo storage (rip) DVD, all'RTP, ai sistemi di telefonia.

– Encoder (percorso in avanti)

Un frame in input o field Fn è processato in unità di un macroblocco.


Ogni macroblocco è encodato in intra o inter e, per ogni blocco del macroblocco,
viene effettuata una predizione PRED (segnata come “P” nella figura soprastante)
basata sui campioni dell'immagine ricostruita.
Nella modalità intra, il PRED è formato dai campioni della parte corrente
precedentemente encodata, decodificata e ricostruita (uF'n in figura;
notare che i campioni “unfiltered” sono usati per formare il PRED).
Nella inter mode (modalità inter), il PRED è formato dalla predizione moto-compensata da una
o due immagini di riferimento selezionate dalle immagini della “lista 0” e/o della “lista 1”.
In figura, l'immagine di riferimento è mostrata come l'immagine precedentemente encodata F'n-1,
ma il riferimento di predizione per ogni partizione di macroblocco (in modalità inter)
potrebbe essere scelto da una selezione di immagini passate o future (in ordine di visualizzazione)
che sono già state encodate, ricostruite e filtrate.
La predizione PRED è sottratta dal blocco corrente per produrre un blocco Dn residuo che è
trasformato (usando una trasformata a blocchi) e quantizzato per dare X,
un set di coefficienti di trasformata quantizzati che sono riordinati dall'encoder entropico.
I coefficienti encodati entropicamente, assieme alle informazioni secondarie richieste
per decodificare ogni blocco nel macroblocco (modelli di predizione, parametri del quantizzatore,
informazioni dei vettori movimento ecc), formano il bit-stream compresso
che è passato al NAL (Network Abstraction Layer) per la trasmissione o lo storage.

– Encoder (percorso di ricostruzione)

Così come encoda e trasmette ogni blocco in un macroblocco, l'encoder decodifica (ricostruisce)
ogni blocco per consentire un riferimento per le predizioni future.
I coefficienti X sono messi in scala (Q^-1) ed inversamente trasformati (T^-1)
per produrre un blocco di differenza D'n.
Il blocco di predizione PRED è aggiunto a quello D'n per creare un blocco ricostruito uF'n:
una versione decodificata del blocco originale, dove “u” indica che è “unfiltered”.
Viene applicato un filtro per ridurre l'effetto di blocking
e poi viene costruita un'immagine di riferimento da una serie di blocchi F'n.

– Decoder

Il decoder riceve il bit-stream compresso dal NAL e decodifica entropicamente i dati


per produrre un set di coefficienti quantizzati X.
Questi sono messi in scala ed inversamente trasformati per dare D'n
(che è identico al D'n dell'encoder).
Utilizzando le informazioni di header decodificate dal bit-stream,
il decoder crea blocchi di predizione PRED (identici agli originali blocchi PRED
formati in fase di encoding) ed i PRED sono poi aggiunti a D'n per produrre uF'n
che è filtrato per creare ogni blocco di decodifica F'n.

– Profile

L'H.264 definisce un set di tre Profiles principali, ognuno dei quali supporta un particolare set di
funzioni di codifica ed ognuno specifica cos'è richiesto ad encoder e decoder
che supportano tale Profile.
Il Profile Baseline supporta la codifica intra ed inter (utilizzando i frame codificati I e P)
e la codifica entropica con codici adattivi al contesto e di lunghezza variabile:
CAVLC (Context Adaptive Variable Length Codes).
Il Profile Main include il supporto ai video interlacciati, la codifica inter utilizzando
i frame codificati B, la codifica inter utilizzando la predizione adattiva e la codifica entropica
utilizzando una codifica aritmetica basata sul contesto:
CABAC (Context Based Arithmetic Coding).
Il profile Extended non supporta i video interlacciati od il CABAC,
ma aggiunge modalità per abilitare uno switch efficiente tra il bit-stream codificato (SP ed SI)
ed una resilienza di errori migliorata (Partizionamento dei Dati).
Ogni Profile ha una flessibilità abbastanza ampia da supportare un vario utilizzo.
Durante gli anni, inoltre, sono stati aggiunti vari profili che sono in grado di coprire una vasta
gamma di applicativi nello specifico, per un totale di 18 profile e 5 sub-profile.

1) Constrained Baseline Profile


Usato principalmente per le videoconferenze e per le applicazioni mobile.

2) Baseline Profile
Usato per le applicazioni a basso costo ed è utilizzato per le videoconferenze
e le applicazioni mobile ed include tutte le feature supportate dal Constrained Baseline
Profile, più altre tre feature.

3) Extended Profile
Usato per lo streaming. Questo profilo ha una capacità di compressione relativamente alta.

4) Main Profile
Questo profilo è utilizzato per il broadcasting televisivo a definizione standard che utilizza
il formato MPEG-4 definito nello standard DVB.

5) High Profile
Utilizzato per il broadcasting ad alta qualità (DVB HDTV) e per i Blu-ray.

6) Progressive High Profile


Molto simile all'High Profile, ma, ovviamente, non supporta la codifica dei field.

7) Constrained High Profile


Simile al Progressive High Profile, ma senza il supporto ai frame codificati B.

8) High 10 Profile (Hi10P)


Questo profilo va oltre alla capacità di decodifica della fascia consumer e consente di
utilizzare 10 bit per campione invece di 8, ma non è supportato dagli applicativi standard
come le console e la maggior parte delle televisioni.

9) High 4:2:2 Profile (Hi422P)


Utilizzato principalmente per gli applicativi professionali che utilizzano video interlacciati.
Questo profilo si basa sul profilo Hi10P aggiungendo il supporto al 4:2:2 per il chroma.

10) High 4:4:4 Predictive Profile (Hi444PP)


Utilizzato per le registrazioni da videocamere professionali, per l'editing professionale
ed altre applicazioni professionali. Questo profilo è basato sull'High 4:2:2,
aggiungendo il supporto al 4:4:4 per il chroma.

11) High 10 Intra Profile


È basato sull'Hi10P ma è limitato a codificare tutti i frame come intra.
12) High 4:2:2 Intra Profile
È basato sull'Hi422P ma è limitato a codificare tutti i frame come intra.

13) High 4:4:4 Intra Profile


È basato sull'Hi444PP ma è limitato a codificare tutti i frame come intra.

14) Stereo High Profile


Utilizzato per la visualizzazione dei video stereoscopici 3D.

15) Multiview High Profile


Utilizzato per la visualizzazione doppia o multipla, ma non supporta le immagini a field.

16) Multiview Depth High profile

17) CAVLC 4:4:4 Intra Profile


È basato sull'Hi444PP ma è limitato a codificare tutti i frame come intra
ed utilizza la codifica entropica CAVLC (ovvero non supporta il CABAC).

Per quanto concerne il CAVLC 4:4:4 Intra Profile, questi contiene a sua volta cinque sub-profile
“scalable”:

17.1) Scalable Baseline Profile


Utilizzato per le video conferenze, per le applicazioni mobile e di sorveglianza.
Questo profilo è basato sul profilo Constrained Baseline al quale il base layer (un subset
del bit-stream) deve essere conforme. Inoltre, per i tool di scalabilità,
è stato abilitato un subset per i tool.

17.2) Scalable Constrained Baseline Profile


Utilizzato principalmente per le comunicazioni in tempo reale.
Questo profilo è basato sul profilo Scalable Baseline.

17.3) Scalable High Profile


Utilizzato principalmente per il broadcasting e lo streaming.
Questo profilo è basato sull'High Profile, al quale il base layer deve essere conforme.

17.4) Scalable Constrained High Profile


Utilizzato principalmente per le comunicazioni in tempo reale.
Questo profilo è basato sul profilo Scalable High.

17.5) Scalable High Intra Profile


Utilizzato principalmente per le applicazioni di produzione.
Questo profilo è basato sul profilo Scalable High, ma codifica tutti i fotogrammi in Intra.

– Levels

Il level è uno specifico set di limitazioni che indicano il “livello” di performance


che il decoder deve avere per poter riprodurre un determinato profile.
Un level specifica la risoluzione massima, il frame rate ed il bitrate che un decoder potrebbe dover
utilizzare e, ovviamente, i decoder che supportano un determinato “level” devono essere in grado
di decodificare tutti i bit-stream encodati per quel livello e tutti quelli ai livelli inferiori.
La maggior parte dei decoder della fascia consumer come le televisioni, le console, nonché i bluray
supportano fino al level 4.1, High Profile (quindi 8 bit con spazio di colore 4:2:0),
per tanto è doveroso rispettare l'authoring per la distribuzione per assicurare la compatibilità.

Il bitrate massimo dell'High Profile è 1.25 volte più alto di quello dei profile Baseline, Extended
e Main.
Il bitrate massimo dell'Hi10P è 3 volte più alto di quello dei profile Baseline, Extended e Main.
Il bitrate massimo dell'Hi444PP è 4 volte più alto di quello dei profile Baseline, Extended e Main.

– Campionamento

L'H.264 supporta la codifica e la decodifica di video progressivi ed interlacciati 4:2:0


e questi è il campionamento di default.
Come visto precedentemenete, è possibile encodare in campioni da 4:2:2 e 4:4:4,
tuttavia la loro decodifica non è supportata dalla maggior parte dei device della fascia consumer
e tali campionamenti sono limitati quasi esclusivamente all'utilizzo in campo professionale.
Nel campionamento di default, le componenti di chroma (Cb e Cr) sono allineate orizzontalmente
con ogni secondo campione di luma e sono situate verticalmente tra i due campioni di luma.

– Formato di Codifica dei Dati

L'H.264 effettua una distinzione tra il VCL (Video Coding Layer)


ed il NAL (Network Abstraction Layer).
L'output del processo di encoding è un dato VCL, ovvero una sequenza di bit che rappresenta
i dati video codificati, che sono mappati in unità NAL prima della trasmissione o dello storage.
Ogni unità NAL contiene un RBSP (Raw Byte Sequence Payload), ovvero un set di dati
che corrispondono ai dati video codificati od alle informazioni di header.
Una sequenza video codificata è rappresentata da una sequenza di unità NAL
che possono essere trasmesse in un network a pacchetti od in un link di trasmissione bit-stream
od anche salvati in un file.

Il fatto di specificare separatamente VCL e NAL è utile in quanto serve a distinguere le feature
specifiche della codifica (VCL) e le feature specifiche del trasporto (NAL),
ma parlerò di quest'ultimo più avanti.

– Reference frame e Slice

L'H.264, in fase di encoding, potrebbe utilizzare una o più immagini precedentemente encodate
come riferimento per la predizione moto-compensata di ogni macroblocco
o partizioni di macroblocco codificati inter.
Questo consente all'encoder di cercare il miglior riferimento per la partizione di macroblocco
corrente da un'ampia gamma di immagini, invece che usare l'immagine precedentemente encodata.
L'encoder ed il decoder mantengono una o due liste di immagini di riferimento,
contenenti immagini che sono state precedentemente encodate e decodificate
(che si verificano prima e/o dopo l'immagine corrente nell'ordine di riproduzione).
I macroblocchi codificati inter e le partizioni di macroblocchi codificate in P
sono predetti dalle immagini in una sola lista: la “lista 0”, già incontrata precedentemente.
I macroblocchi codificati inter e la partizioni di macroblocchi codificate in B
potrebbero invece essere predette da due liste: la “lista 0” e la “lista 1”.
In precedenza è stata trattata la codifica in Intra (I), Predicted (P) e Bi-predictive (B), ma l'H.264,
per il profile Extended, fa utilizzo anche dello Switching P (SP) e dello Switching I (SI).
Nell'H.264, inoltre, questi assumono il nome di “Slice”.
Un'immagine video è quindi codificata come uno o più Slice, ognuno contentente un numero intero
di macroblocchi che va da 1 (1 MB per Slice) al numero totale di macroblocchi nell'immagine
(1 Slice per immagine).
Il numero di macroblocchi per Slice non deve essere costante nell'immagine
e c'è una interdipendenza minimale tra gli Slice codificati
che può aiutare a limitare la propagazione degli errori.
Ci sono cinque tipi di Slice codificati (ovvero I, P, B, SP ed SI) ed un'immagine codificata
potrebbe contenere un misto di Slice I e P; ad esempio, un'immagine codificata con il Main
e l'Extended profile potrebbe contenere un misto di slice I, P e B.
Lo Slice header definisce il tipo di Slice e l'immagine codificata cui appartiene lo Slice
e può contenere istruzioni relative alla gestione dell'immagine di riferimento.
Il dato Slice consiste in una serie di macroblocchi codificati ed/o un'indicazione di macroblocchi
skippati (non codificati) ed ogni macroblocco contiene una serie di elementi header
e dati residui codificati.
Gli Slice Intra contengono solo macroblocchi Intra.
Gli Slice P contengono macroblocchi P e/o macroblocchi codificati I.
Per quanto riguarda quelli codificati P, ogni macroblocco (o partizione di questo)
è predetto da un'immagine di riferimento contenuta nella lista 0.
Gli Slice B contengono macroblocchi B e/o macroblocchi I.
Per quanto riguarda quelli codificati B, ogni macroblocco (o partizione di questo)
è predetto da un'immagine di riferimento contenuta nella “lista 0” e/o nella “lista 1”.
Gli Slice Switching P (SP) servono a facilitare lo switch tra gli stream codificati
e contengono macroblocchi P e/o I.
Gli Slice Switching I (SI), invece, servono a facilitare lo switch tra gli stream codificati
e contengono macroblocchi SI, ovvero un particolare tipo di macroblocco codificato Intra.

– I Macroblocchi

Un macroblocco contiene dati codificati corrispondenti a regioni campione del frame video 16x16
(16x16 campioni luma, 8x8 campioni Cb ed 8x8 campioni Cr) e contiene elementi di sintassi
mb_type, mb_pred, sub_mb_pred, coded_block_pattern, mb_qp_delta e residual.
L'mb_type determina se il macroblocco è codificato in intra o inter (P o B)
e determina la grandezza di partizione del macroblocco.
L'mb_pred determina la modalità di predizione intra (macroblocchi intra) e determina i riferimenti
in lista 0 e/o lista 1 ed i vettori di movimento codificati per ogni partizione di macroblocco
(macroblocchi inter, eccetto per i macroblocchi inter con grandezza di partizione 8x8).
Il Sub_mb_pred è solo per i macroblocchi inter con grandezza di partizione 8x8 e determina la
grandezza di partizione del sotto-macroblocco per ogni sotto-macroblocco,
i riferimenti appartenenti alla lista 0 e/o lista 1 per ogni partizione di macroblocco
ed i vettori movimento codificati per ogni sotto-partizione di macroblocco.
Il code_block_pattern identifica quali blocchi 8x8 (luma e chroma) contengono i coefficienti di
trasformata codificati.
L'mb_qp_delta cambia il parametro del quantizzatore.
Il residual definisce i coefficienti di trasformata codificati
corrispondenti ai campioni di immagine residua dopo la predizione.
– Il Profilo Baseline

Il profilo Baseline supporta la codifica delle sequenze video contenenti Slice I e P.


Gli Slice I contengono macroblocchi codificati intra nei quali le regioni di luma da 16x16 o 4x4
e quelle da 8x8 del chroma sono predette dal campione precedentemente codificato
nello stesso Slice.
Gli Slice P possono contenere macroblocchi codificati intra, codificati inter o skippati.
I macroblocchi codificati inter in uno Slice P sono predetti da un numero di immagini codificate
precedentemente utilizzando la compensazione di movimento con accuratezza
di un vettore movimento di un quarto di campione (luma).
Dopo la predizione, i dati residui per ogni macroblocco
sono trasformati usando una trasformata intera 4x4 (basata sulla DCT) e quantizzati.
I coefficienti di trasformata quantizzati sono riordinati
e gli elementi di sintassi sono codificati entropicamente.
Nel profilo Baseline, i coefficienti di trasformata sono codificati entropicamente utilizzando
lo schema CAVLC (Context adaptive variable length coding) già trovato in precedenza e tutti gli
altri elementi di sintassi sono codificati utilizzando una lunghezza fissata
o i codici di lunghezza variabile Golomb-Esp.
I coefficienti quantizzati sono messi in scala, inversamente trasformati, ricostruiti
(aggiunti alla predizione formata in fase di encoding) e filtrati con un filtro di deblocking
(a discrezione dell'encoder) prima di essere salvati per un possibile uso nelle immagini
di riferimento per macroblocchi intra ed inter futuri.
Dopo questa visione generale del Baseline profile,
è lecito passare ad esplicare come viene effettuata la gestione delle immagini di riferimento.
Le immagini che sono state encodate precedentemente sono salvate nel buffer di riferimento
(il buffer delle immagini decodificate, detto DPB, decoded picture buffer)
sia nell'encoder che nel decoder.
L'encoder ed il decoder mantengono una lista di immagini codificate precedentemente,
la lista 0 di immagini di riferimento, per l'utilizzo nelle predizioni moto-compensate
di macroblocchi inter in Slice P.
Per la predizione degli Slice P, la lista 0 contiene immagini prima e dopo l'immagine corrente
(nell'ordine di riproduzione) e possono contenere immagini di riferimento sia “short term”
sia “long term”.
Di default, un'immagine encodata è ricostruita dall'encoder e markata come immagine “short term”,
ovvero un'immagine recentemente codificata che è disponibile per la predizione.
Le immagini “short term” sono identificate dal “PicNum”, una variabile derivata
dal loro numero di frame. Le immagini “long term” sono, in genere, le immagini più “vecchie”
che possono essere utilizzate per la predizione e sono identificate da un LTPN (Long Term PicNum)
variabile.
Le immagini “long term” rimangono nel DPB (decoded picture buffer)
finché non vengono esplicitamente rimosse o sostituite.
Quando un'immagine è encodata e ricostruita (nell'encoder) o decodificata (nel decoder),
è inserita nel DPB e può essere marcata come “a” (non utilizzabile per i riferimenti),
come “b” (short term), come “c” (long term) o come “d” (semplice output al display).
Di default, le immagini “short term” nella lista 0 sono ordinate secondo il PicNum,
dal più alto al più basso e le immagini “long term” sono ordinate dall'LTPN (Long Term PicNum)
più basso a quello più alto; ad ogni modo, l'encoder può segnalare un cambiamento nell'ordine
della lista delle immagini di riferimento di default.
Come ogni nuova immagine è aggiunta alla lista “short term” in posizione 0,
gli indici delle immagini “short term” rimanenti sono incrementati.
Se il numero degli “short term” e dei “long term” è uguale al massimo numero di reference frame,
l'immagine “short term” più “vecchia” (cioè con l'indice più alto) è rimossa dal buffer;
questo processo è conosciuto come controllo di memoria “sliding window” - finestra scorrevole.
L'effetto di questo processo è che l'encoder ed il decoder mantengono una “finestra” di N immagini
di riferimento “short term”, inclusa l'immagine corrente
ed (N-1) immagini precedentemente encodate.
I comandi di controllo memoria adattiva inviati dall'encoder gestiscono gli index d'immagine
“short term” e “long term”.
Utilizzando questi comandi, le immagini “short term” possono essere assegnate ad un frame index
“long term” oppure un'immagine “short term” o “long term” può essere marcata come
“non utilizzabile come riferimento”.
L'encoder sceglie l'immagine di riferimento dalla lista 0 per encodare
ogni partizione di macroblocco in un macroblocco codificato inter.
La scelta dell'immagine di riferimento è segnalata da un numero di index, dove l'index 0
corrisponde al primo frame nella sezione “short term” e gli indici dei frame “long term”
iniziano dopo l'ultimo “short term”.
Procedendo oltre, un encoder manda anche un'immagine codificata IDR (Instantaneous Decoder
Refresh) - fatta di Slice I o SI - per chiarire i contenuti del buffer dell'immagine di riferimento.
Quando riceve un'immagine codificata IDR, il decoder marca tutte le immagini nel buffer di
riferimento come “non utilizzabile come riferimento”.
Tutti gli Slice trasmessi di seguito possono essere decodificati senza riferimento
ad alcuna immagine decodificata prima dell'immagine IDR
e la prima immagine in una sequenza video codificata è sempre un'immagine IDR.
Un bit-stream conforme al profilo Baseline contiene Slice codificati I e/o P.
Uno Slice I contiene solo macroblocchi codificati intra (predetti dai campioni codificati in
precedenza nello stesso Slice) ed uno Slice P può contenere macroblocchi codificati inter
(predetti da campioni nelle immagini precedentemente codificate),
macroblocchi codificati intra o macroblocchi skippati.
Quando un macroblocco skippato è segnalato nel bit-stream,
non sono inviati ulteriori dati per quel macroblocco.
Il decoder calcola un vettore per il macroblocco skippato e ricostruisce il macroblocco
utilizzando la predizione moto-compensata dalla prima immagine di riferimento nella lista 0.
Un encoder H.264 può inserire opzionalmente un'unità RBSP delimitante
ai bordi delle immagini codificate.
Questo per indicare l'inizio di una nuova immagine codificata ed indicare quali tipi di Slice
sono consentiti nell'immagine codificata seguente.
Se il delimitatore non è utilizzato, il decoder cerca le informazioni sul verificarsi dei nuovi frame
nell'header del primo Slice nella nuova immagine.
Passando oltre, un'immagine marcata come “ridondante” contiene una rappresentazione parziale
o completa dell'immagine codificata.
Nelle operazioni normali, il decoder ricostruisce il frame dalla prima immagine non ridondante
e dimentica ogni immagine ridondante.
Ad ogni modo, se la prima immagine codificata è danneggiata (ad esempio a causa di un errore
di trasmissione), il decoder può decidere di sostituire l'area danneggiata con i dati decodificati
di un'immagine ridondante, se disponibile.
Tornando a parlare degli Slice, è doveroso introdurre l'ASO (Arbitrary Slice Order) –
ordine degli Slice arbitrario.
Il profilo baseline supporta l'ASO ed utilizzare questo tool significa semplicemente
che gli Slice in un frame codificato possono seguire qualsiasi ordine di decodifica.
L'ASO è definito per essere utilizzato se il primo macroblocco in uno Slice in un frame decodificato
contiene un indirizzo di macroblocco più piccolo del primo macroblocco in uno Slice decodificato
precedentemente nella stessa immagine.
Sempre parlando di Slice, ci sono anche i “Gruppi di Slice”.
Un gruppo di slice è un subset (sottoinsieme) dei macroblocchi in un'immagine codificata
e può contenere uno o più Slice.
All'interno di ogni Slice in un gruppo di Slice, i macroblocchi sono codificati in ordine raster.
Se è utilizzato un solo gruppo di Slice per immagine, allora tutti i macroblocchi nell'immagine
sono codificati in ordine raster (a meno che l'ASO sia in uso).
Più gruppi di Slice (descritti nelle precedenti versioni dello standard come “FMO” - Flexible
Macroblock Ordering) rendono possibile la mappatura della sequenza di macroblocchi codificati
all'immagine decodificata in tanti modi flessibili.
L'allocazione di macroblocchi è determinata da una “mappatura di macroblocco a gruppo di Slice”
che indica a quale gruppo di Slice appartiene ogni macroblocco
e ci sono 6 tipi di mappatura di macroblocco a gruppo di Slice.
Tipo 0, l'interleaved: i macroblocchi run_length sono assegnati ad ogni gruppo di Slice.
Tipo 1, Dispersed: i macroblocchi in ogni gruppo di Slice sono “dispersi”nell'immagine.
Tipo 2, Foreground and Background: tutti i gruppi di Slice tranne l'ultimo sono definiti
come regioni rettangolari all'interno dell'immagine. L'ultimo gruppo di Slice
contiene tutti i macroblocchi non contenuti in ogni altro gruppo di Slice (il “background”).
Tipo 3, Box-out: viene creato un “box” a partire dal centro del frame (con la grandezza controllata
dai paramentri dell'encoder) che contiene il gruppo 0,
mentre tutti gli altri macroblocchi sono nel gruppo 1.
Tipo 4, Raster scan: il gruppo 0 contiene i macroblocchi nell'ordine di scansione raster
dall'alto a sinistra e tutti gli altri macroblocchi sono nel gruppo 1.
Tipo 5, Wipe: il gruppo 0 contiene i macroblocchi in ordine di scansione verticale
dall'alto a sinistra e tutti i macroblocchi sono in gruppo 1.
Tipo 6, Explicit: è inviato un parametro, lo slice_group_id, per ogni macroblocco
per indicare il suo gruppo di Slice, ovvero la mappatura del macroblocco
è totalmente definita dall'utente.
Dopo aver parlato dei sei tipi di mappatura, sempre all'interno del profilo baseline,
è doveroso trattare la predizione dei macroblocchi.
Ogni macroblocco codificato in uno Slice H.264 è predetto da un dato encodato precedentemente.
I campioni all'interno di un macroblocco sono predetti da campioni nello slice corrente
che è già stato encodato, decodificato e ricostruito ed i campioni in un macroblocco inter
sono predetti da quelli encodati precedentemente.
Viene creata una predizione per il macroblocco - o blocco - corrente (un modello che è il più simile
possibile al macroblocco - o blocco - corrente) dal campione d'immagine che è già stato encodato
(sia nello stesso Slice che nello Slice precedentemente encodato).
Questa predizione è sottratta dal macroblocco - o blocco - corrente ed il risultato della sottrazione
(residuo) è compresso e trasmesso al decoder, assieme all'informazione richiesta dal decoder
per ripetere il processo di predizione (vettori movimento, modalità di predizione ecc).
Il decoder crea una predizione identica ed aggiunge questa al residuo o blocco decodificato.
L'encoder basa la sua predizione sui campioni d'immagine encodati e decodificati (piuttosto che sui
campioni di frame video originali) in modo da assicurarsi che le predizioni di encoder e decoder
siano identiche.
Parlando di predizioni, la predizione inter crea un modello di predizione da uno o più frame o field
video precedentemente encodati utilizzando la moto-compensazione basata sui blocchi.
Le differenze importanti dagli standard precedenti includono il supporto ad un ampio raggio
di dimensioni di blocco (da 16x16 a 4x4) e dei precisi sotto-campioni di vettori movimento
(risoluzione di un quarto di campione nella componente di luma).
Nel profilo baseline la componente di luma di ogni macroblocco sono campioni 16x16 che possono
essere divisi in quattro modi e moto-compensati come una partizione di macroblocco univoca
da 16x16, come due partizioni da 16x8, due partizioni da 8x16 o quattro partizioni da 8x8.
Se viene selezionata la modalità 8x8, ogni sotto-macroblocco (quattro da 8x8) all'interno
del macroblocco può essere diviso in altri 4 modi: come una partizione di sotto-macroblocco
da 8x8, come due partizioni di sotto-macroblocco da 8x4, due partizioni di sotto-macroblocco
da 4x8 o quattro sotto-partizioni da 4x4.
Queste partizioni e questi sotto-macroblocchi danno vita ad un'ampia gamma
di possibili combinazioni all'interno di ogni macroblocco.
Questo metodo di partizionamento dei macroblocchi in sotto-blocchi moto-compensati
di varia grandezza è conosciuto come “moto-compensazione con struttura ad albero”.
È richiesto un vettore movimento separato per ogni partizione o sotto-macroblocco
ed ogni vettore movimento deve essere codificato e trasmesso
e la scelta delle partizioni dev'essere encodata nel bit-stream compresso.
Scegliere una dimensione di partizionamento grande (16x16, 16x8, 8x16) significa che
sarà richiesto un numero di bit minore per segnalare la scelta dei vettori movimento
ed il tipo di partizione, ma i residui di motocompensazione potrebbero contenere una quantità
di energia significativa nelle aree di frame ad alto dettaglio.
Scegliere una dimensione di partizionamento piccola (8x4, 4x4, ecc) potrà anche dare residui
con minore energia dopo la moto-compensazione, ma richiede un numero di bit maggiore
per segnalare i vettori movimento ed il tipo di partizione.
Dunque, la scelta della dimensione di partizionamento ha un impatto significativo
sulle performance di compressione.
In generale, una partizione grande è appropriata per le aree omogenee del frame
ed una partizione piccola è utile per le aree con più dettaglio, come i lineamenti nei volti ecc.

Ogni componente di chroma (Cb e Cr) in un macroblocco ha metà risoluzione orizzontale


e metà risoluzione verticale della componente di luma.
Ogni blocco di chroma è partizionato nello stesso modo di quello della componente di luma,
eccetto per il fatto che la dimensione di partizionamento ha esattamente metà risoluzione
orizzontale e verticale; in altre parole, una partizione da 8x16 di luma corrisponde
ad una partizione da 4x8 nel chroma ed una partizione di 8x4 nel luma
corrisponde ad una di 4x2 nel chroma e così via e le componenti orizzontale e verticale di ogni
vettore movimento (uno per partizione) sono dimezzate quando applicate ai blocchi di chroma.
Nell'immagine sottostante è possibile vedere la scelta della dimensione di partizionamento
per il luma in un frame residuo (senza motocompensazione).

È possibile notare come per le parti meno dettagliate – come quelle dello sfondo – siano stati scelti
blocchi da 16x16, mentre per quelle più dettagliate – come i lineamenti dei volti o i bordi del libro –
sono stati scelti blocchi più piccoli o sotto-blocchi.
Finora ho parlato molto dei vettori movimento, ma non ho mai analizzato il loro funzionamento e,
dunque, è lecito nonché opportuno esplicarlo.
Come sappiamo, ogni partizione o partizione di sotto-macroblocco in un macroblocco codificato
inter è predetta da un'area della stessa dimensione nell'immagine di riferimento.
L'offset tra le due aree (il vettore movimento) ha risoluzione di un quarto di campione
per la componente di luma e di un ottavo di campione per le componenti di chroma.
I campioni di luma e chroma nelle posizioni di sotto-campionamento non esistono nell'immagine di
riferimento, per cui è necessario crearli utilizzando un'interpolazione tra i campioni vicini codificati.
Nell'immagine soprastante il frame corrente (a) è predetto da una regione dell'immagine
di riferimento nelle vicinanze della posizione del blocco corrente.
Se le componenti orizzontale e verticale del vettore movimento sono interi (b),
i campioni rilevanti nel blocco di riferimento esistono (notare i pallini grigi).
Se una od entrambe le componenti di vettore sono valori frazionari (c), i campioni di predizione (i
pallini grigi) sono generati dall'interpolazione tra i campioni adiacenti
ed i frame di riferimento (pallini bianchi).
È dunque lecito domandarsi come vengono generati nello specifico i campioni interpolati.
Ebbene, i campioni a metà strada tra i campioni di posizione intera (detti “campioni half-pel”)
nella componente di luma dell'immagine di riferimento sono generati per primi
e sono rappresentati nell'immagine sottostante.

Ogni campione “half-pel” adiacente a due campioni interi (b, m, s, h) è interpolato dai campioni
di posizione intera utilizzando un filtro FIR (Finite Inpulse Response) a sei passi
da 1/32, -5/32, 5/8, 5/8, -5/32. 1/32.
Ad esempio, il campione “half-pel” b è calcolato dai sei campioni interi orizzontali E, F, G, H, I, J.
Abbiamo dunque b = [(E – 5F + 20G + 20H - 5I + J) / 32].
In modo del tutto affine, h è interpolato da A, C, G, M, R, T.
Quando tutti i campioni orizzontali e verticali adiacenti ai campioni interi sono stati calcolati,
le posizioni “half-pel” rimanenti sono calcolate interpolando sei campioni orizzontali o verticali
“half-pel” dal primo set di operazioni.
Ad esempio, j è generato da cc, dd, h, m, ee, ff ed il risultato è lo stesso sia interpolando j
orizzontalmente, sia interpolandolo verticalmente; inoltre, per generare j,
vengono utilizzate le versioni non arrotondate di h ed m.
L'interpolazione a sei passi è relativamente complessa,
ma produce dei buoni risultati ai campioni di dati interi e, quindi, una buona moto-compensazione.
Quando tutti i campioni “half-pel” sono disponibili, i campioni al quarto passo
(chiamati “quarter-pel”) sono prodotti da un'interpolazione lineare.
Le posizioni “quarter-pel” con due campioni di posizione intera o a metà orizzontali o verticali
(a, e, c, i, k e d, f, n, q) sono interpolati linearmente tra i campioni adiacenti.
Ad esempio, per a abbiamo: a = [(G + b) / 2].
Le posizioni “quarter-pel” rimanenti (e, g, p ed r in figura) sono interpolate linearmente
tra le coppie di campioni “half-pel” diagonalmente opposte; ad esempio, e è interpolato tra b ed h.
I vettori movimento “quarter-pel” nella componente di luma richiedono vettori di otto campioni
nella componente del chroma nel campionamento 4:2:0.
I campioni interpolati sono generati ad intervalli di 8 campioni tra i campioni interi
in ogni componente di chroma utilizzando l'interpolazione lineare.

Ogni posizione a di sotto-campione è una combinazione lineare dei campioni interi vicini
di posizione A, B, C e D.

Precisamente, nell'immagine di sopra, abbiamo che dx è uguale a 2 e che dy è uguale a 3, quindi:

I vettori movimento per ogni partizione possono richiedere un significativo numero di bit,
specialmente se sono scelte partizioni di grandezza ridotta.
I vettori movimento delle partizioni vicine di solito sono molto correlati, quindi
ogni vettore movimento è predetto dai vettori di partizioni vicine precedentemente codificate.
Un vettore predetto, MVp (Motion Vector predicted), è formato a partire dai vettori movimento
precedentemente calcolati e la MVD (Motion Vector Difference),
ovvero la differenza tra il vettore corrente ed il vettore predetto, è encodata e trasmessa.
Il metodo di creazione delle predizioni MVp dipende dalla grandezza di partizione
della moto-compensazione e dalla disponibilità dei vettori vicini.

Supponiamo che E sia il macroblocco corrente, partizione di macroblocco o


partizione di sotto-macroblocco.
Supponiamo che A sia la partizione o sotto-partizione immediatamente a sinistra di E.
Supponiamo che B sia la partizione o sotto-partizione immediatamente sopra E.
Supponiamo infine che C sia la partizione o partizione di sotto-macroblocco sopra ed a destra di E.
Se ci sono più di una partizione immediatamente a sinistra di E,
la partizione più alta viene scelta come A.
Se ci sono più di una partizione immediatamente sopra E,
la partizione più a sinistra viene scelta come B.
Se tutte le partizioni hanno la stessa grandezza, si verifica la situazione riportata
nella figura soprastante e le partizioni sono da 16x16 (in questo caso).
Se invece le partizioni vicine hanno una grandezza differente da quelle vicine,
si ha la situazione riportata nell'immagine sottostante.

Per le partizioni trasmesse escluse quelle da 16x8 ed 8x16, la MVp (Motion Vector predition)
è la media dei vettori movimento per le partizioni A, B e C.
Per le partizioni 16x8, la MVp per la partizione superiore è predetta da B
e la MVp per la partizione inferiore è predetta da A.
Per le partizioni 8x16, la MVp per la partizione sinistra è predetta da A
e la MVp per la partizione destra è predetta da C.
Per i macroblocchi skippati la MVp è generata come se il blocco fosse encodato in 16x16
in modalità inter.
Se uno (o più blocchi) precedentemente trasmessi non è disponibile
(ad esempio, se è fuori dallo Slice corrente), la scelta della MVp varia di conseguenza.
Nella fase di decodifica, la MVp è formata nello stesso modo
ed aggiunta alla MVD (Motion Vector Difference).
Nel caso di un macroblocco skippato, non c'è alcun vettore differenza decodificato
ed il macroblocco moto-compensato è prodotto usando la MVp come vettore movimento.
Procedendo oltre, per quanto riguarda la modalità intra, un blocco di predizione P
è formato partendo dai blocchi precedentemente encodati e ricostruiti
ed è sottratto dal blocco corrente prima dell'encoding.
Per i campioni di luma, P è formato per ogni blocco 4x4 o per un macroblocco da 16x16.
Ci sono un totale di nove possibili modalità di predizione per ogni blocco 4x4 di luma,
quattro modalità per il blocco di luma da 16x16 e quattro modalità per le componenti di chroma.
L'encoder generalmente sceglie la modalità di predizione per ogni blocco
che minimalizza la differenza tra P ed il blocco da encodare.
Un'altra modalità di codifica intra, l'LPCM, abilita l'encoder a trasmettere i valori dei campioni
dell'immagine direttamente (cioè senza predizione o trasformazione).
In alcuni casi particolari (si parla di contenuti anomali e/o con bassissimi parametri
di quantizzazione), questa modalità può risultare essere più efficiente rispetto al “solito”
processo di predizione intra, trasformazione, quantizzazione e codifica entropica.
Includendo la modalità LPCM, è possibile porre un limite assoluto sul numero di bit
che possono essere contenuti in un macroblocco codificato
senza vincolare la qualità dell'immagine decodificata.

La figura soprastante ha un macroblocco evidenziato che deve essere predetto.


Il campione in alto a sinistra (segnato come M-A in figura) è stato precedentemente encodato e
ricostruito ed è dunque disponibile nell'encoder e nel decoder come riferimento per una predizione.
I campioni a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p del blocco di predizione P sono calcolati
in base ai campioni A-M come segue.

Modalità 0 (Verticale): i campioni superiori A, B, C, D sono estrapolati verticalmente.


Modalità 1 (Orizzontale): i campioni di sinistra I, J, K, L sono estrapolati orizzontalmente.
Modalità 2 (DC): tutti i campioni in P sono predetti dalla media dei campioni A...D ed I...L.
Modalità 3 (Diagonale inferiore sinistra): i campioni sono interpolati ad un angolo di 45°
tra l'inferiore sinistro ed il superiore destro.
Modalità 4 (Diagonale inferiore destra): i campioni sono estrapolati ad un angolo di 45°
in basso a destra.
Modalità 5 (Verticale Destra): estrapolazione ad un angolo di circa 26.6° a sinistra della verticale
(larghezza/altezza = ½).
Modalità 6 (Orizzontale inferiore): estrapolazione ad un angolo di circa 26.6° sotto l'orizzontale.
Modalità 7 (Verticale sinistra): estrapolazione (o interpolazione) ad un angolo di circa 26.6°
a destra della verticale.
Modalità 8 (Orizzontale superiore): interpolazione ad un angolo di circa 26.6° sopra l'orizzontale.
Nella modalità 2, la predizione DC è modificata a seconda di quali campioni A-M
sono stati encodati precedentemente e le altre modalità possono essere utilizzate
solo se tutti i campioni di predizione richiesti sono disponibili.
Da notare che se i campioni E, F, G ed H non sono stati ancora decodificati,
il valore del campione D è copiato in queste posizioni
e queste vengono marcate come “disponibili”.
Per le modalità 3-8 i campioni di predizione sono formati da una media pesata
dei campioni di predizioni A-M.
Ad esempio, se viene scelta la modalità 4, il campione in alto a destra di P
(chiamato “d” nell'immagine precedente) è predetto da: B/4 + C/2 + D/4.
Come alternativa alla modalità 4x4 del luma descritta precedentemente,
l'intera componente da 16x16 di un macroblocco può essere predetta in un'operazione.
Sono disponibili quattro modalità che vanno da 0 a 3.

Modalità 0 (Verticale): estrapolazione dai campioni superiori (H).


Modalità 1 (orizzontale): estrapolazione dai campioni sinistri (V).
Modalità 2 (DC): media dei campioni superiori e sinistri (H + V)
Modalità 3 (Planare): una funzione lineare “planare” è applicata ai campioni superiori e sinistri
H e V e funziona particolarmente bene nelle aree con luma variabile.
Per quanto riguarda invece il chroma, ogni componente di chroma 8x8 di un macroblocco
codificato intra è predetta da campioni di chroma precedentemente encodati superiori e/o sinistri
ed entrambe le componenti di chroma utilizzano sempre la stessa modalità di predizione.
Le quattro modalità di predizione sono molto simili alla predizione da 16x16 del luma
descritta un attimo fa e riportata nella figura soprastante, ma la numerazione delle modalità
è differente: la modalità 0 è la DC, la modalità 1 è quella orizzontale,
la modalità 2 è quella verticale e la modalità 3 è quella planare.
Comunque, la scelta di una modalità di predizione intra per ogni blocco da 4x4 deve essere
segnalata al decoder e questo potrebbe potenzialmente richiedere un grande numero di bit.
Ad ogni modo, con le modalità intra per i blocchi da 4x4 vicini, questi sono spesso correlati.
Ad esempio, supponiamo che A, B ed E siano macroblocchi da 4x4 rispettivamente sinistro,
superiore e corrente.
Se i blocchi 4x4 A e B precedentemente encodati sono predetti utilizzando la modalità 1, è
probabile che la miglior modalità per il blocco E (cioè il blocco corrente) sia sempre la modalità 1.
Per poter sfruttare la correlazione, per segnalare le modalità intra da 4x4
viene usata la codifica predittiva.
Per ogni blocco corrente E, l'encoder ed il decoder calcolano la modalità di predizione
più probabile, il minimo delle modalità di predizione di A e B.
Se entrambi i blocchi vicini non sono disponibili (sono esterni allo Slice attuale o non codificati
in modalità intra 4x4), il varo corrispondente A o B è settato a 2 (modalità di predizione DC).
L'encoder invia un flag per ogni blocco 4x4, prev_intra4x4_pred_mode.
Se il flag è “l”, viene utilizzata la modalità di predizione più probabile.
Se il flag è “0”, viene mandato un altro parametro rem_intra4x4_pred_mode
per indicare un cambiamento di modalità.
Se rem_intra4x4_pred_mode è più piccolo della modalità più probabile corrente, allora la modalità
di predizione è settata su rem_intra4x4_pred_mode,
altrimenti la modalità di predizione è settata su rem_intra4x4_pred_mode+1.
In questo modo, solo otto valori di rem_intra4x4_pred_mode sono richiesti (da 0 a 7)
per segnalare la modalità intra corrente (da 0 a 8).
La modalità di predizione per il luma codificato in modalità intra 16x16 o per il chroma codificato
in modalità intra è segnalata nell'header del macroblocco e la codifica predittiva della modalità
non è utilizzata in questi casi.

Procedendo oltre, il profilo baseline (così come gli altri profili) supporta un filtro di deblocking
per evitare di produrre spiacevoli artefatti dovuti alla compressione.
Il fenomeno del blocking e le sue cause sono state affrontate precedentemente ed era stata proposta
come soluzione l'utilizzo di un diverso tipo di codifica tramite trasformata,
ovvero quello adottato dal JPEG 2000.
Ebbene, l'H.264 offre una soluzione – se così si può chiamare – al fenomeno di blocking
dovuto alla compressione che altro non è che un filtro di deblocking.
Il filtro viene applicato dopo la trasformata inversa prima di ricostruire e salvare il macroblocco
per le predizioni future nell'encoder e prima di ricostruire e riprodurre il macroblocco nel decoder.
Il filtro “leviga” le estremità dei blocchi, migliorando l'aspetto dei frame ricostruiti
e l'immagine filtrata è utilizzata per la predizione moto-compensata di frame futuri.
L'encoder può decidere di attivare o disattivare il filtro,
così come di regolarne i parametri di strength e trashold che vanno da 0 a -6 e da 0 a 6.
I valori da 0 a -6 effettuano un deblocking più leggero, atto alla conservazione dei dettagli.
I valori da 0 a 6 effettuano un deblocking più pesante, atto alla rimozione degli artefatti di blocking.
Generalmente, vengono utilizzati valori di strength 1 e treshold 1 per le animazioni e di -1, -1
per i film, dove il è presente più dettaglio.

Di default, il filtraggio è applicato alle estremità orizzontali e verticali dei blocchi 4x4 in un
macroblocco (eccetto per le estremità ai bordi degli Slice) e viene rispettato il seguente ordine:
1 – Vengono filtrati 4 bordi verticali della componente di luma (a, b, c, d).
2 – Vengono filtrati 4 bordi orizzontali della componente di luma (e, f, g, h).
3 – Vengono filtrati 2 bordi verticali di ogni componente di chroma (i, j).
4 – Vengono filtrati 2 bordi orizzontali di ogni componente di chroma (k, l).
Ogni operazione di filtraggio coinvolge tre campioni in ogni parte del bordo.
Per una migliore compresione, si osservi la figura sottostante.

L'immagine rappresenta 4 campioni di ogni lato del bordo (orizzontale e verticale)


nei blocchi adiacenti (p0, p1, p2, p3 e q0, q1, q2, q3).
L'intensità del filtro dipende dal quantizzatore corrente, dalla modalità di codifica,
dai blocchi vicini e dal gradiente dei campioni di immagine attraverso il bordo.
La scelta di filtrare dipende dalla “boundary strength” (forza di bordo)
e dal gradiente dei campioni di immagine attraverso il bordo.
Il parametro di “boundary strength” è chiamato “bS” ed è scelto secondo le seguenti regole
(per i frame progressivi):
bS = 4: p e/o q sono codificati intra ed il bordo è il bordo di un macroblocco.
bS = 3: p e q sono codificati intra ed il bordo non è il bordo di un macroblocco.
bS = 2: p o q non è codificato intra; p e q contengono coefficienti codificati.
bS = 1 p o q non è codificato intra; p o q non contengono coefficienti codificati;
p e q utilizzano immagini di riferimento diverse o un diverso numero di immagini di riferimento
od hanno valori di vettore movimento che differiscono di un campione di luma o più,
altrimenti: bS = 0.
Il risultato di applicare queste regole è che il filtro è più forte dove c'è un blocking maggiore, come,
ad esempio, ai bordi di un macroblocco codificato intra o
in un bordo tra blocchi contenenti coefficienti codificati.
Per quanto riguarda la decisione di filtraggio, un gruppo di campioni dal set (p2, p1, p0, q0, q1, q2)
è filtrato se e solo se bS è maggiore di zero, | p0 – q0| è minore di Alpha, |p1 – p0| è minore di Beta
e |q1 – q0| è minore o uguale a beta.
Alpha e Beta sono i thresholds definiti nello standard
ed aumentano col parametro di quantizzazione media QP dei due blocchi p e q.
L'effetto della decisione di filtraggio è che è possibile “spegnere” il filtro quando c'è
un cambiamento significativo (gradiente) attraverso il bordo del blocco nell'immagine originale.
Quando il QP è piccolo, probabilmente c'è solo un piccolo gradiente attraverso il bordo
e tutto il resto è semplicemente il dettaglio dell'immagine stessa e non un effetto di blocking e,
proprio perché deve essere conservato, i thresholds di Alpha e Beta sono bassi.
Quando il QP è grande, l'effetto di blocking, probabilmente, è più marcato
ed Alpha e Beta sono più alti in modo da filtrare più campioni di bordo.
Prendiamo in esame il macroblocco di luma da 16x16 rappresentato nell'immagine sottostante.
All'interno del macroblocco sono stati rappresentati 4 blocchi da 4x4 chiamati a, b, c, d.
Presupponendo che il QP abbia un valore medio-alto, il bordo di blocco tra a e b verrà
probabilmente filtrato perché il gradiente attraverso questo bordo è piccolo.
Non ci sono dettagli dell'immagine significativi da dover preservare
ed ovviamente questa presenterà artefatti di blocking se non filtrato.
Ad ogni modo, c'è un significativo cambiamento nel luma attraverso il bordo tra c e d a causa del
dettaglio orizzontale dell'immagine, per cui il filtro viene “spento” per preservare tale dettaglio.
Osserviamo ora il suo funzionamento a livello analitico ed individuiamo due casi: A e B.
Nel caso A, abbiamo bS ∈ {1,2,3} e viene applicato un filtro a 4 passate agli input p1, p0, q0 e q1,
producendo output filtrati p'0 e q'0.
Se |p2 – p0| è minore del threshold Beta, viene applicato un altro filtro a quattro passate con input
p2, p1, p0 e q0, producendo un output filtrato p'1 (solo luma).
Se |q2 – q0| è minore del threshold Beta, viene applicato un filtro a quattro passate con input q2, q1,
q0 e p0, producendo un output filtrato q'1 (solo luma).
Nel caso B, abbiamo bS = 4.
Se |p2 – p0| è minore di Beta e |p0 – q0| è minore dell'intorno Alpha/4 ed è un blocco di luma:
p'0 è prodotto dal filtraggio a 5 passate di p2, p1, p0, q0 e q1,
p'1 è prodotto dal filtraggio a 4 passate di p2, p1, p0 e q0,
p'2 è prodotto dal filtraggio a 5 passate di p3, p2, p1, p0 e q0.
Altrimenti p'0 è prodotto dal filtraggio a tre passate di p1, p0 e q1.
Se |q2 – q0| è minore di Beta e |p0 – q0| è minore dell'intorno Alpha/4 ed è un blocco di luma:
q'0 è prodotto da un filtraggio a cinque passate di q2, q1, q0, p0 e p1,
q'1 è prodotto da un filtraggio a quattro passate di q2, q1, q0 e p0,
q'2 è prodotto da un filtraggio a cinque passate di q3, q2, q1, q0 e p0.
Altrimenti q'0 è prodotto da un filtraggio a tre passate di q1, q0 e p1.
Dopo aver analizzato il filtro di deblocking, è opportuno mostrare un esempio.
Prendiamo come esempio il seguente frame:

Encodiamo ora tale frame con una quantizzazione costante di 36 (che è molto alta).
Disabilitando il filtro di deblocking, il risultato è rappresentato nella seguente immagine nella quale
è possibile notare grandi artefatti di blocking.
Ovviamente, l'alta quantizzazione ha creato questi artefatti che sono molto utili a livello di studio
poiché è possibile notare i residui della moto-compensazione già affrontata in precedenza.
È curioso difatti vedere come, nello sfondo, è possibile notare i blocchi da 16x16 (blocchi grandi),
mentre il volto e, soprattutto, la mano destra (in movimento ed ad alto dettaglio)
è formata da blocchi da 4x4.
Ripetiamo ora lo stesso encoding ma con il filtro di deblocking attivato:

È possibile notare che la maggior parte dell'effetto di blocking è scomparso e l'immagine è


chiaramente starvata (soffre di carenza di bitrate),
ma è decisamente più piacevole all'occhio dell'immagine precedente.
È inoltre possibile osservare come i bordi ad alto contrasto (come il contorno del braccio in
contrasto con il pianoforte scuro) sono stati conservati.
I bordi dei blocchi appartenenti a regioni piane (come il muro sullo sfondo), invece,
sono stati smussati.
Per eseguire tale comparison è stata encodata una sequenza in entrambi i modi
e sono stati infine selezionati gli stessi frame per poterli comparare.
È stato dunque possibile osservare l'efficienza di compressione in termini di peso del video finale.
In questo esempio il contributo del filtro di deblocking è minimo, ad ogni modo, la qualità visiva
è decisamente migliore, quindi è comunque positivo utilizzarlo.
Ripetendo l'encoding a quantizzazione costante 32, è possibile vedere ancora come il filtro di
deblocking viene in aiuto (prima immagine senza deblocking, seconda immagine con il
deblocking):
Per la rappresentazione di tali esempi ho parlato di encoding a quantizzazione costante.
Ebbene, l'H.264 utilizza due trasformate a seconda del tipo di dato residuo che deve essere
codificato: la trasformata di Walsh-Hadamard per l'array di 4x4 dei coefficienti DC di luma nei
macroblocchi intra predetti in modalità 16x16, la trasformata di Walsh-Hadamard per l'array di 2x2
dei coefficienti DC del chroma (in ogni macroblocco) e la Trasformata Discreta del Coseno per tutti
gli altri blocchi da 4x4 nei dati residui.

I dati all'interno del macroblocco sono trasmessi in un determinato ordine.


Se il macroblocco è codificato in modalità intra 16x16, il blocco viene segnato come “-1”,
contiene i coefficienti trasformati DC di ogni blocco di luma da 4x4 ed è trasmesso per primo.
Poi, i blocchi residui di luma 0-15 sono trasmessi in un determinato ordine
(ma i coefficienti DC nel macroblocco codificato in modalità intra 16x16 non sono inviati).
I blocchi 16 e 17 sono inviati e contengono un array di 2x2 dei coefficienti DC
rispettivamente dai componenti di chroma Cb e Cr.
Infine, i blocchi di chroma residui 18-25 (senza i coefficienti DC) sono inviati.
Per i blocchi di dati residui – segnati come 0-15 e 18-25 in figura – dopo la predizione di moto-
compensazione e la predizione intra, viene effettuata un'operazione di trasformata DCT; in realtà
tale trasformata non è la DCT, ma è basata sulla DCT, ed ha alcune differenze fondamentali:

1) È una trasformata intera (tutte le operazioni possono essere svolte utilizzando l'aritmetica
degli interi, senza perdita dell'accuratezza di codifica).
2) È possibile assicurare una differenza pari a zero nell'operazione di trasformata inversa tra
encoder e decoder (grazie all'aritmetica degli interi).
3) La moltiplicazione scalare (parte della trasformata) è integrata nel quantizzatore, riducendo
il numero totale di moltiplicazioni.

Le operazioni di quantizzazione inversa e quella di trasformata inversa possono essere svolte con
l'aritmetica degli interi a 16 bit (eccetto alcuni casi in cui ci sono alcuni residui anomali) con un
solo multiplo per coefficiente, senza alcuna perdita di precisione.
La DCT per i blocchi 4x4 è data da:
dove:

Questa moltiplicazione di matrice può essere fattorizzata alla sequente forma:

CXC^T è una trasformata bidimensionale. E è una matrice di fattori di scala ed il simbolo ⊗ indica
che ogni elemento della CXT^T è moltiplicato dal fattore di scala nella stessa posizione
nella matrice E (moltiplicazione scalare invece della moltiplicazione di matrice).
Le costanti a e b sono come prima e d è c/b (approssimativamente 0.414).
Per semplificare l'implementazione della trasformata, d è approssimato a 0.5.
Per essere sicuri che la trasformata rimanga ortogonale, b ha bisogno di essere modificato così che:

La seconda riga e la quarta riga della matrice C e la seconda e la quarta colonna della matrice C^T
sono scalate da un fattore di due e la matrice E post-scalatura è scalata per compensare,
evitando la moltiplicazione per metà nella trasformata bidimensionale CXC^T
che potrebbe risultare in una perdita di accuratezza utilizzando l'aritmetica ad interi.
La trasformata in avanti finale diventa:

Questa trasformata è un'approssimazione della DCT 4x4, ma a causa del cambiamento apportato ai
fattori d e b, il risultato della nuova trasformata non sarà identico a quello della DCT 4x4.
Per rendersi conto delle differenze tra le due, è opportuno servirsi di un esempio.
Supponiamo di avere il seguente blocco da 4x4:

L'output della DCT originale è:


L'output della trasformata approssimata è invece:

Per meglio notare le differenze, è stata apportata la sottrazione tra l'output della DCT originale (Y)
e quello della trasformata approssimata (Y'):

C'è una chiara differenza tra i coefficienti di output che dipendono da b o d.


Nel contesto del codec H.264, la trasformata approssimata ha una performance di compressione
quasi identica a quella della DCT ed ha numerosi vantaggi.
La trasformata bidimensionale CXC^T può essere effettuata con l'aritmetica degli interi,
utilizzando solamente addizioni, sottrazioni e spostamenti.
Il range dinamico delle operazioni di trasformata è tale che l'aritmetica a 16 bit può essere utilizzata
tranquillamente (eccetto per alcuni casi anomali, come già detto sopra),
dato che gli input sono nel range – 255 + 255.
Le operazioni post-scalatura ⊗Ef richiedono una moltiplicazione per ogni coefficiente
che può essere “assorbito” nel processo di quantizzazione.
La trasformata inversa è data dalla sequente equazione e lo standard H.264
definisce tale trasformata come una sequenza di operazione aritmetiche:

Questa volta, Y è pre-scalato moltiplicando ogni coefficiente con un fattore di pesatura appropriato
dato dalla matrice Ei.
Da notare che i fattori ±1/2 nelle matrici C e C^T possono essere implementati da uno spostamento
a destra senza una perdita significativa di accuratezza poiché i coefficienti Y sono pre-scalati.
Infine, ricordo che le trasformate in avanti ed inversa sono ortogonali, ovvero:

Per quanto riguarda la quantizzazione, l'H.264 utilizza una quantizzazione scalare.


Il meccanismo di quantizzazione in avanti ed inversa hanno due requisiti principali:
1) Evitare la divisione e/o l'aritmetica a virgola mobile.
2) Incorporare le matrici post e pre-scalatura Ef ed Ei.
L'operazione di quantizzazione in avanti di base è:

Dove Yij è un coefficiente della trasformata descritta sopra,


Qstep è la grandezza del passo di quantizzazione e Zij è un coefficiente quantizzato.
Sono supportati 52 valori in totale per il Qstep,
indexati da un parametro di quantizzazione QP (Quantisation Parameter).
Il Qstep raddoppia in grandezza per ogni incremento di 6 nel parametro di quantizzazione QP.
L'ampio range di passi di quantizzazione fa sì che l'encoder possa controllare il “compromesso”
tra bitrate e qualità in modo accurato e flessibile.
I valori del parametro di quantizzazione QP possono essere differenti per luma e chroma.
Entrambi i parametri sono nel range di 0-51 e di default il parametro del chroma Qpc
è derivato da Qpy in modo che Qpc sia minore di Qpy per Qpy maggiore di 30.

Esiste inoltre un dato chiamato Picture Parameter Set


nel quale è possibile segnalare una mappatura definita dall'utente tra Qpy e Qpc.
I fattori post-scalatura a^2, ab/2 o b^2/4 dell'equazione trattata sopra
sono incorporati nella quantizzazione in avanti.
Per prima cosa, il blocco in input X è trasformato per dare un blocco di coefficienti non scalati
W = CXC^T.
Poi, ogni coefficiente Wij è quantizzato e scalato in una singola operazione:

PF è a^2, ab/2 o b^2/4 a seconda della posizione (i, j).

Per semplificare l'aritmetica, il fattore PF/Qstep è implementato nel “Reference model software”
come una moltiplicazione di un fattore MF ed uno spostamento a destra,
evitando ogni operazione di divisione:

dove

che nell'aritmetica ad interi può essere implementata come:

dove “>>” indica uno spostamento binario a destra. Nel “Reference Model Software”,
f è 2^gbits /3 per i blocchi intra o 2^gbits /6 per i blocchi inter.
Il “Reference Model Software” è un'implementazione software
che può essere scaricata gratuitamente e serve per dare un esempio del codec,
piuttosto che essere un'applicazione utilizzabile per sé (come è invece x264).
Il Reference Model Software utilizzato in questa tesi è la versione JM6.1b.
I primi sei valori di MF (per ogni posizione di coefficiente) utilizzati dal Reference Software
Encoder dell'H.264 sono riportati nell'immagine soprastante.
La seconda e la terza colonna dell'immagine (posizioni coi fattori b^2 /4 e ab/2)
sono stati leggermente modificati dai risultati dell'equazione vista in precedenza.
Di fatto, è possibile modificare la quantizzazione in avanti in modo da aumentare, per dire,
la qualità percepita in fase di decoding, visto che solo il processo di rescaling (la quantizzazione
inversa) è standardizzato.
Per QP maggiore di 5, i fattori MF rimangono invariati, ma il divisore 2^gbits aumenta di un fattore
di due per ogni incremento di sei in QP; ad esempio, avremo qbits = 16 per QP compreso tra 6 e 11,
qbits = 17 per QP compreso tra 12 e 17 e così via.
Per quanto concerne il rescaling (quantizzazione inversa), invece, l'operazione è:

Il fattore di pre-scaling per la trasformata inversa (dalla matrice Ei, contenente valori a^2, ab e b^2
a seconda della posizione del coefficiente) è incorporato in questa operazione,
assieme al fattore di scalatura costante di 64 per evitare errori di approssimazione:

W'ij è un coefficiente scalato che è trasformato dalla trasformata inversa:

I valori all'output della trasformata inversa sono divisi per 64 per rimuovere il fattore di scalatura
(questo può essere implementato usando solo l'addizione e lo spostamento a destra).
Lo standard H.264 non specifica il Qstep od il PF direttamente.
Difatti, il parametro V = (Qstep.Pf.64) è definito per QP compreso tra 0 e 5
e per ogni posizione di coefficiente in modo che l'operazione di scalatura diventi:

Il fattore 2^floor(QP/6) nell'equazione riportata sopra


causa l'aumento dell'output scalato di un fattore di due per ogni incremento di 6 nel QP.
I valori di V definiti nello standard per QP compreso tra 0 e 5 sono riportati nella tabella sottostante:

Se il macroblocco è encodato nella modalità di predizione intra da 16x16 (ovvero l'intera


componente luma da 16x16 è predetta dai campioni vicini), ogni blocco residuo da 4x4
è prima trasformato utilizzando la trasformata descritta sopra:

Il coefficiente DC di ogni blocco 4x4 è poi trasformato ancora utilizzando la trasformata di Walsh-
Hadamard a 4x4:
WD è il blocco di coefficienti DC da 4x4 e YD è il blocco dopo la trasformazione.
I coefficienti di output YD(i, j) sono quantizzati per produrre un blocco di coefficienti quantizzati DC:

MF(0,0) è il fattore di moltiplicazione per la posizione (0, 0) nella tabella riportata sopra
precedentemente ed f e qbits sono definiti come prima.
In fase di decoding, viene applicata la trasformata di Walsh-Hadamard inversa,
seguita da un rescaling (ma l'ordine non è ripristinato come si potrebbe invece pensare):

Lo scaling del decoder è fatto da:

V(0,0) è il fattore di scala V per la posizione (0, 0) nella tabella riportata di sopra precedentemente.
Siccome V(0,0) è costante durante il blocco, il rescaling e la trasformata inversa
possono essere applicati in qualsiasi ordine.
L'ordine specificato (prima la trasformata inversa, poi lo scaling) è designato per massimizzare
il range dinamico della trasformata inversa.
I coefficienti DC riscalati W'D sono inseriti nei rispettivi blocchi da 4x4 ed ogni blocco di
coefficienti da 4x4 è inversamente trasformato utilizzando la trasformata inversa basata sulla DCT:

In un macroblocco 16x16 codificato intra, la maggior parte dell'energia


è concentrata nei coefficienti DC di ogni blocco da 4x4 che tendono ad essere altamente correlati.
Dopo questa trasformazione extra, l'energia è concentrata ulteriormente
in un piccolo numero di coefficienti significativi.
Ogni blocco da 4x4 nelle componenti del chroma è trasformato come descritto precedentemente.
I coefficienti DC di ogni blocco da 4x4 dei coefficienti del chroma sono raggruppati in blocchi
da 2x2 (WD) e sono trasformati ulteriormente prima della quantizzazione:

La quantizzazione del blocco YD di output è data da:

MF(0,0) è il fattore di moltiplicazione per la posizione (0, 0) ed f e qbits sono definiti come prima.
Durante la fase di decoding, la trasformata inversa è applicata prima dello scaling:

Lo scaling è effettuato da:

I coefficienti ri-scalati sono sostituiti nei rispettivi blocchi da 4x4 dei coefficienti del chroma
che sono trasformati come sopra.
Per quanto riguarda i coefficienti DC intra del luma, la trasformata extra aiuta a de-correlare
i coefficienti DC del chroma da 2x2 ed aumenta le performance di compressione.
Il processo completo da un blocco X residuo di input ad un blocco X' residuo di output
è descritto di seguito:

Encoding:
1) Input: campioni residui da 4x4, X
2) Trasformata in avanti (non la DCT originale):

(seguita da una trasformata in avanti per i coefficienti DC del chroma o per gli intra-16 del luma)
3) post-scalatura e quantizzazione:

(differente per DC del chroma o DC intra-16 del luma).


Decoding:
4) Scaling del decoder:

(differente per DC del chroma o DC intra-16 del luma).


5) Trasformata inversa (non la trasformata inversa DCT originale):

6) post-scalatura:

7) Output dei campioni residui da 4x4: X''

Per chiarire il tutto, è lecito procedere con un esempio.


Supponiamo di avere un QP = 10
Il blocco in input X è:

L'output della trasformata W (non la DCT originale) è:

MF = 8192, 3355 o 5243 a seconda della posizione del coefficiente.


qbits = 16.
f = 2^qbits /3.
L'output della quantizzazione in avanti Z è:

V = 16, 25 o 20 a seconda della posizione.


2^floor (QP/6) = 2^1 cioè 2.
L'output del rescale W' è:

L'output della trasformata inversa X'' (non la trasformata inversa DCT originale)
dopo la divisione per 64 ed approssimazione è:

Nella figura sottostante è infine rappresentata la scansione zig-zag per un blocco da 4x4 del luma
(modalità frame):

Passiamo quindi ora ad esplicare la fase di riordinamento.


Nell'encoder, ogni blocco da 4x4 di coefficienti di trasformata quantizzati è mappato in un array
di 16 elementi in ordine a zig zag, come mostrato nella figura soprastante, appunto.
In un macroblocco encodato in modalità intra da 16x16, i coefficienti DC (in alto a sinistra)
di ogni blocco di luma da 4x4 sono scansionati e questi coefficienti DC formano un array da 4x4
che è scansionato nell'ordine mostrato sempre dalla figura soprastante.
Questo lascia 15 coefficienti AC in ogni blocco di luma
che sono scansionati a partire dalla seconda posizione.
Allo stesso modo, i coefficienti DC da 2x2 di ogni componente di chroma sono scansionati
(in ordine raster) e poi i 15 coefficienti AC di ogni blocco da 4x4 del chroma
sono scansionati a partire dalla seconda posizione.
Al di sopra dello slice layer, gli elementi di sintassi sono encodati come codici binari
di lunghezza fissata o variabile.
Allo slice layer e sotto, gli elementi sono codificati utilizzando sia codici a lunghezza variabile
(VLC – Variable Length Codes) che la codifica ad aritmetica adattiva al contesto (CABAC –
Context Adaptive Based Arithmetic Coding) a seconda della modalità dell'encoder entropico.
Quando l'entropy_coding_mode (modalità di codifica entropica) è settata su 0, i dati dei blocchi
residui sono encodati utilizzando uno schema di codifica adattiva al contesto di lunghezza variabile
(CAVLC – Context Adaptive Variable Length Coding) e sono codificate altre unità
codificate a lunghezza varibile utilizzando i codici Exp-Golomb.
I parametri che devono essere encodati e trasmessi includono i seguenti:

– Elementi di sintassi sequence-, picture- e slice-layer (contengono gli header ed i parametri).


– Tipo di macroblocco mb_type (contiene il metodo di predizione per ogni macroblocco
codificato).
– Pattern del blocco codificato (indica quali blocchi all'interno del macroblocco contengono i
coefficienti codificati).
– Parametro di quantizzazione (è trasmesso come un valore delta dal precedente valore di QP).
– Index di reference frame (identifica i reference frame per la predizione inter).
– Vettore movimento (trasmesso come differenza – differenza di vettore movimento –
dal un vettore movimento predetto).
– Dati resudui (coefficiente di dati per ogni blocco da 4x4 o 2x2).

Sono stati nominati prima i codici Exp-Golomb ed è quindi bene affrontare


anche la codifica entropica Exp-Golomb.
I codici Exp-Golomb (che sta per “Exponential Golomb”) sono codici di lunghezza variabile
con una costruzione regolare e basta esaminare le prime parole di codice per rendersene conto:

[M zero][1][INFO]

INFO è un field di M-bit che contiene le informazioni.


La prima parola di codice non ha zero iniziali o INFO.
Le parole di codice 1 e 2 hanno un campo INFO di un solo bit, le parole di codice 3-6
hanno un campo INFO a due bit e così via.
La lunghezza di ogni parola di codice Exp-Golomb è (2M + 1) bit ed ogni parola di codice
può essere costruita dall'encoder sulla base del suo index code_num:

Una parola di codice può essere decodificata come segue:

1) Leggere M zero seguiti da 1.


2) Leggere M-bit campi INFO.
3) code_num = 2^M + INFO – 1.

Un parametro k che deve essere encodato è mappato al code_num nelle seguenti maniere:

– ue: mappatura diretta unsigned; code_num=k. Viene utilizzato per il tipo di macroblocco,
per l'index di reference frame ed altre cose.
– te: una versione della tabella di parole di codice Exp-Golomb nella quale le parole di codice
corte sono troncate.
– se: mappatura “signed”; utilizzata per la differenza di vettori movimento, per il delta QP ed
altre cose.

Code_num=2|k| (k minore o uguale a 0)


Code_num=2|k|-1 (k maggiore di 0)

– me: simboli mappati; il parametro k è mappato al code_num secondo la tabella specificata


nello standard.

Di seguito è riportata una piccola parte del coded_block_pattern per i macroblocchi predetti Inter,
indicando quali blocchi da 8x8 in un macroblocco contengono coefficienti non zero:

Ognuna di queste mappature (ue, te, se ed me) è designata per produrre parole di codice brevi
per valori che si presentano frequentemente e parole di codice più lunghe per valori meno ricorrenti.
Ad esempio, al macroblocco inter P_L_0_16x16 (predizione di una partizione di luma da 16x16 da
un'immagine precedente) è assegnato il code_num 0 perché si presenta frequentemente
ed al macroblocco P_8x8 (predizione di una partizione di luma da 8x8 da un'immagine precedente)
è assegnato il code_num 3 perché si presenta meno frequentemente.
Infine, la differenza di vettore movimento (MVD – Motion Vector Difference)
comunemente ricorrente di valore 0 è mappata al code_num 0,
mentre l'MVD meno ricorrente = -3 è mappato al code_num 6.
Per quanto riguarda la CAVLC citata in precedenza (Codifica a lunghezza variabile adattiva al
contesto), questa è utilizzata per encodare i blocchi residui da 4x4 (e 2x2) ordinati a zig zag
dei coefficienti di trasformata e si serve di numerose caratteristiche dei blocchi da 4x4 quantizzati:

1) Dopo la predizione, la trasformazione e la quantizzazione, i blocchi sono tipicamente sparsi


(contengono per lo più zero). La CAVLC utilizza una codifica a livello di esecuzione
per rappresentare stringhe di zero in modo compatto.

2) I coefficienti non zero più alti dopo la scansione a zig zag sono solitamente sequenze di ±1 e
la CAVLC segnala il numero di coefficienti ad alta frequenza ±1 “TrailingOnes”
in modo compatto.

3) Il numero di coefficienti non zero nei blocchi vicini è correlato.


Il numero di coefficienti è encodato utilizzando una tabella scelta
e tale scelta dipende proprio dal numero di coefficienti non zero nei blocchi vicini.

4) Il livello (magnitudine) dei coefficienti non zero tende ad essere più grande all'inizio
dell'array riordinato (vicino ai coefficienti DC) e più piccolo intorno alle alte frequenze.
La CAVLC trae vantaggio da questa cosa adattando la scelta della tavola VLC per il
parametro “livello” basato sul livello delle magnitudini recentemente codificate.

La codifica CAVLC encoda un blocco di coefficienti di trasformata come segue:

– 1.coeff_token: encoda il numero di coefficienti non zero “TotalCoeff”


ed i “TrailingOnes” (uno per blocco).

– 2.trailing_ones_sign_flag: segno/flag per il valore TrailingOne.

– 3.level_prefix: prima parte di codice per i coefficienti non zero (uno per coefficiente,
escludendo i TrailingOnes).

– 3.1level_suffix: seconda parte del codice per i coefficienti non zero (non sempre presente).

– 4.total_zeros: encoda il numero totale di zero che si verificano


dopo il primo coefficiente non zero (nell'ordine a zig zag; uno per blocco).

– 5.run_before: encoda il numero di zero precedente ogni coefficiente non zero


nell'ordine di zig zag inverso.

1.coeff_token:
Il primo VLC, il coeff_token, encoda sia il numero totale di coefficienti non zero (TotalCoeffs)
che il numero di valori ±1 “TrailingOnes”.
Il “TotalCoeffs” può essere qualsiasi valore da 0 (non ci sono coefficienti nel blocco da 4x4)
a 16 (16 coefficienti non zero) ed il “TrailingOnes” può essere qualsiasi valore da 0 a 3.
Se ci sono più di tre trailing ±1s, solo gli ultimi tre sono trattati come “casi speciali”
e gli altri sono codificati come normali coefficienti.
Ci sono quattro scelte da usare come tabella per l'encoding del coeff_token per un blocco di 4x4;
tre tavole di codice a lunghezza variabile ed un tavolo a lunghezza fissa.
La scelta del tavolo dipende dal numero di coefficienti non zero
nei blocchi codificati precedentemente a sinistra e superiori (rispettivamente nA e nB)
e viene calcolato un parametro nC.
Se i blocchi superiore e sinistro nB ed nA sono entrambi disponibili
(ovvero nello stesso slice codificato):

Se è disponibile solo quello superiore: nC=nB.


Se è disponibile solo quello sinistro: nC=nA.
Se nessun blocco è disponibile: nC=0.
Il parametro nC seleziona la tabella in modo che la scelta del VLC si adatti
al numero di coefficienti codificati nei blocchi vicini (adattiva al contesto).
La tabella 1 è fatta per un piccolo numero di coefficienti in modo che bassi valori di TotalCoeffs
sono assegnati a codici particolarmente corti
ed alti valori di TotalCoeff sono assegnati a codici particolarmente lunghi.
La tabella 2 è fatta per coefficienti di numero medio (valori di TotalCoeff di 2-4 sono assegnati a
codici relativamente corti).
La tabella 3 è fatta per i coefficienti di grande numero e la tabella 4 assegna un codice fissato
di 6 bit ad ogni coppia di valori TotalCoeff e TrailingOnes.

2.trailing_ones:
Per ogni TrailingOne (±1) segnalato dal coeff_token, il segno è encodato con un singolo bit
(0 = +, 1 = -) in ordine inverso, a partire dal TrailingOne di frequenza più alta.

3.level_prefix e 3.1 level_suffix:


Il level (segno e magnitudine) di ogni coefficiente non zero rimanente nel blocco è encodato
in ordine inverso, partendo dalla frequenza più alta e lavorando sui coefficienti DC.
Il codice per ogni level è fatto da un prefix (level_prefix) ed un suffix (level_suffix).
La lunghezza del suffisso (suffixLength) può essere tra 0 e 6 bit e la suffixLength è adattata
a seconda della magnitudine di ogni level codificato successivo (adattiva al contesto).
Un basso valore di suffixLength è adatto a level con basse magnitudini
ed un alto valore di suffixLength è adatto a level con alte magnitudini.
La scelta del suffixLength è fatta come segue:

1) Inizializzazione del suffixLength a 0 (a meno che non ci siano più di 10 coefficienti non
zero e meno di tre TrailingOnes; in tal caso, il suffixLength viene inizializzato ad 1).
2) Encoding del coefficiente non zero di frequenza più alta.
3) Se la magnitudine di questo coefficiente è più grande del threshold predefinito,
il suffixLength viene incrementato. (Se p è il primo level ad essere encodato
ed il suffixLength era inizializzato a 0, il suffixLength viene settato a 2).

In questo modo, la scelta del suffix (e quindi il VLC completo)


è concordato con la magnitudine dei coefficienti recentemente encodati.
I threshold sono mostrati nell'immagine di seguito:

Il primo threshold è zero, il che significa che il suffixLength è sempre incrementato


dopo che il primo level di coefficiente è stato encodato.

4.total_zeros:
La somma di tutti gli zero precedenti il coefficiente non zero più alto nell'array riordinato
è codificata con la VLC; zero totali.
Il motivo dietro al fatto di inviare un dato VLC separato per indicare gli zero totali
è che molti blocchi contengono un certo numero di coefficienti non zero all'inizio dell'array
e questo approccio fa sì che i primi zero all'inizio dell'array non debbano essere encodati.

5.run_before:
Il numero di zero precedenti ogni coefficiente non zero (run_before) è encodato in ordine inverso.
Viene encodato un parametro run_before per ogni coefficiente non zero,
a partire dalla frequenza più alta, con due eccezioni:

a) se non ci sono più zero da encodare, non è necessario encodare altri valori di run_before.
b) non è necessario encodare il run_before per il coefficiente finale non zero (frequenza più bassa).

La VLC per ogni run di zero è scelta a seconda del numero di zero
che non sono stati ancora encodati (ZerosLeft) e dal run_before.
Ad esempio, se ci sono rimasti solo due zero da encodare, run_before può assumere solamente
tre valori (0, 1 o 2) così che non c'è bisogno che il VLC sia più lungo di due bit.
Se ci sono sei zero ancora da encodare, allora il run_before può assumere sette valori (da 0 a 6)
e la tabella VLC deve essere corrispondentemente grande.
Prima di passare al main profile, è bene chiarire quest'ultima parte con degli esempi.
Prendiamo come primo esempio il seguente blocco da 4x4:

blocco riordintato:

TotalCoeffs = 5 (indexati dalla frequenza più alta – 4 – alla frequenza più bassa – 0 –).
total_zeros = 3.
TrailingOnes = 3 (ci sono, in effetti, 4 TrailingOnes, ma solo tre possono essere encodati come
“casi speciali”, come già detto precedentemente.
Encoding:
Il bit-stream trasmesso per questo blocco è:

Decoding:

L'array di output è creato dai valori decodificati


e sono evidenziati di seguito i valori aggiunti all'array di output ad ogni stadio:

Il decoder ha già inserito due zero: il TotalZeros è uguale a 3 così che un altro zero è inserito prima
del coefficiente più basso, facendo sì che l'array finale di output sia:

Procediamo ora con un altro esempio.


Supponiamo di avere il seguente blocco da 4x4:
blocco riordinato:

TotalCoeffs = 5 (indexato dalla frequenza più alta – 4 – a quella più bassa – 0 –)


total_zeros = 2.
TrailingOne = 1.

Encoding:

Il bitstream trasmesso per questo blocco è:

Soffermandoci sulla tabella precedente, è possibile notare che il Level (3), con un valore di -3,
è encodato come caso speciale.
Se ci sono meno di 3 TrailingOnes, allora il primo level non TrailingOne
non può avere un valore di ±1 (altrimenti sarebbe stato encodato come TrailingOne).
Per poter salvare bit, questo level è incrementato se negativo (e decrementato se positivo)
in modo che ±2 mappa ±1; ±3 mappa ±2 e così via;
in questo modo, vengono utilizzati VLC più corti.
Dopo aver encodato il level (3), level_VLC è incrementato
perché la magnitudine di questo level è più grande del primo threshold (che è zero).
Dopo l'encoding del level(1), con una magnitudine di 4,
viene incrementato ancora perché il level(1) è più grande del secondo threshold (che è 3).
È da sottolineare infine che il level finale (-2) utilizza un VLC differente dal primo level encodato
(anch'esso -2).

Decoding:
Tutti gli zero sono stati ora decodificati e l'array di output è:

Procediamo ora con un ultimo esempio; supponiamo di avere il seguente blocco da 4x4:

blocco riordinato:

TotalCoeffs = 3 (indexati dalla frequenza più alta – 2 – a quella più bassa – 0 –).
total_zeros = 7.
TrailingOnes = 3.

Encoding:

Il bit-stream trasmesso per questo blocco è:

Decoding:

Il decoder ha inserito quattro zero: il total_zero è uguale a 7 in modo che altri tre zero
sono inseriti prima del coefficiente più basso:

Con questo si chiude la parte dedicata al profilo Baseline


ed è possibile quindi passare ad analizzare il Main Profile, implementato per applicativi differenti.
– Il Main Profile

Gli applicativi del Main Profile riguardano il broadcasting


(televisioni digitali) e lo storage dei video digitali.
Il Main Profile è una sorta di “soprainsieme” del profilo Baseline, tranne per il fatto che i gruppi
di slice multipli, l'ASO e gli slice ridondanti (tutti inclusi nel profilo Baseline) non sono supportati.
Gli strumenti aggiuntivi utilizzati dal Main Profile sono i B slice (slice “bi-predicted”
per una migliore efficienza di codifica), la predizione pesata (che garantisce una maggiore
flessibilità nel creare blocchi di predizione moto-compensati), il supporto ai video interlacciati
(la codifica dei field oltre a quella dei frame) ed il CABAC
(un metodo di codifica entropica alternativo basato sulla codifica aritmetica).
Cominciamo dunque ad analizzare gli strumenti aggiuntivi e partiamo proprio dai B slice.
Ogni partizione di macroblocco in un macroblocco codificato inter in un B slice può essere predetto
da una o due immagini di riferimento, prima o dopo l'immagine corrente (in ordine temporale).
A seconda delle immagini di riferimento salvate nell'encoder e nel decoder,
è possibile avere più opzioni per scegliere i riferimenti di predizione
per le partizioni di macroblocco in un macroblocco di tipo B.
Osserviamo ora la seguente figura:

La figura soprastante raffigura tre esempi: il primo (a) è un riferimento passato ed un riferimento
futuro (simile alla predizione delle immagini B già affrontata nei precedenti video standard MPEG);
il secondo (b) mostra due riferimenti passati ed il terzo (c) mostra due riferimenti futuri.
Gli slice B utilizzano due liste di immagini di riferimento precedentemente encodate: la lista 0
e la lista 1, contenenti immagini a breve ed a lungo termine, come già affrontato in precedenza.
Queste due liste possono contenere immagini codificate passate e/o future (immagini antecedenti
o precedenti all'immagine corrente nell'ordine di riproduzione).
Le immagini a lungo termine in ogni lista si comportano in modo simile a quanto descritto
quando ho trattato le immagini di riferimento in precedenza.
Le immagini a breve termine, invece, possono essere immagini codificate passate e/o future
e l'ordine d'index di default di queste immagini è il seguente:

– Lista 0: all'immagine passata più vicina (sulla base dell'ordine di conteggio delle immagini)
è assegnato index 0, seguita da ogni altra immagine passata (aumentando l'ordine di
conteggio delle immagini), seguita da ogni altra immagine futura (aumentando l'ordine di
conteggio delle immagini dall'immagine corrente).
– Lista 1: all'immagine futura più vicina è assegnato index 0, seguita da ogni altra immagine
futura, seguita da ogni immagine passata.
Facciamo un esempio: supponiamo che un decoder H.264 salvi 6 immagini di riferimento a breve
termine con ordine di conteggio delle immagini 123, 125, 126, 128, 129, 130.
L'immagine corrente è numerata 127.
Tutte e sei le immagini di riferimento a breve termine sono marcate come “usate per il riferimento”
nella lista 0 e nella lista 1.
Le immagini sono indexate nelle liste 0 ed 1 del buffer a breve termine:

Nei macroblocchi B slice ci sono le seguenti opzioni:

– partizione da 16x16: diretta, lista 0, lista 1, bi-predictive.

– partizione da 16x8 o 8x16: lista 0, lista 1, bi-predictive (scelta separatamente


per ogni partizione).

– partizione da 8x8: diretta, lista 0, lista 1, bi-predictive (scelta separatamente


per ogni partizione).

Il buffer index selezionato è inviato come parola di codice Exp-Golomb (già affrontata
in precedenza) in modo che venga indexata come 0 la scelta più efficiente di index di riferimento
(con la parola di codice più corta), ovvero l'immagine precedentemente codificata nella lista 0
e l'immagine successivamente codificata nella lista 1.
Per quanto concerne le opzioni di predizione, le partizioni di macroblocchi in uno slice B
possono essere predette in varie maniere: in modalità diretta, da una predizione moto-compensata
da un'immagine di riferimento appartenente alla lista 0, da una predizione moto-compensata
da un'immagine di riferimento appartenente alla lista 1
o anche da una predizione moto-compensata bi-predictive appartenente alla lista 0 o alla lista 1.
Le diverse modalità di predizione possono essere scelte per ogni partizione;
se è utilizzata una partizione di grandezza 8x8, la modalità scelta per ogni partizione 8x8
è applicata a tutte le sotto-partizioni all'interno di quella partizione.

La figura soprastante mostra due esempi di combinazioni di modalità di predizione validi.


A sinsitra, abbiamo due partizioni da 16x8 che utilizzano rispettivamente la lista 0
e la predizione bi-predictive ed a destra abbiamo quattro partizioni da 8x8
che utilizzano la predizione diretta, la lista 0, la lista 1 e la predizione bi-predictive.
Nella modalità bi-predictive, il blocco di riferimento (della stessa grandezza del macroblocco di
partizione o sotto-macroblocco di partizione) è creato dalle immagini di riferimento della lista 0 e
della lista 1. Due aree di riferimento moto-compensate sono ottenute dalle immagini rispettivamente
della lista 0 e della lista 1 (e quindi sono richiesti due vettori movimento) ed ogni campione di
blocco di predizione è calcolato come una media dei campioni di predizione della lista 0
e della lista 1.
Ad eccezione di quando viene utilizzata la predizione pesata, viene utilizzata la seguente equazione:

pred0(i,j) e pred1(i, j) sono campioni di predizione derivati dalle immagini di riferimento


della lista 0 e della lista 1 e pred(i, j) è un campione bi-predictive.
Dopo aver calcolato ogni campione di predizione, il residuo moto-compensato
è creato dalla sottrazione del pred(i, j) da ogni campione del macroblocco corrente, come al solito.
Per una maggiore comprensione, supponiamo di avere, per esempio, un macroblocco predetto in
modalità B_Bi_16x16 (ovvero bi-prediction del macroblocco completo). Osserviamo di seguito le
aree di riferimento ottenute dalle immagini di riferimento della lista 0

e quelle della lista 1:

Di seguito è infine mostrata la bi-prediction formata dalle due aree di riferimento


(predizione non pesata):
I vettori della lista 0 e della lista 1 in un macroblocco bi-predictive (o blocco) sono predetti dai
vettori movimento vicini che hanno la stessa direzione temporale; ad esempio, un vettore per il
macroblocco corrente che punta ad un frame passato è predetto da altri vettori vicini che puntano
anch'essi a dei frame passati.
Per quanto riguarda la predizione diretta, invece, non viene trasmesso alcun vettore movimento
per un macroblocco (o partizione di macroblocco) B slice encodato in modalità diretta.
Infatti, il decoder calcola i vettori della lista 0 e della lista 1 sulla base dei vettori precedentemente
codificati ed utilizza questi vettori per la moto-compensazione bi-predictive dei campioni residui
decodificati. Un macroblocco skippato in un B slice, ad esempio, è ricostruito dal decoder
utilizzando proprio la predizione diretta.
Un flag nello slice header indica se verrà utilizzato un metodo spaziale o temporale
per calcolare i vettori per i macroblocchi o partizioni in modalità diretta.
Procediamo ora col riportare la modalità di calcolo per i vettori predetti della lista 0 e della lista 1
nella modalità diretta spaziale.
I vettori di predizione della lista 0 e della lista 1 sono calcolati utilizzando lo stesso identico metodo
già affrontato in precedenza. Se il macroblocco co-locato o la partizione nella prima immagine di
riferimento della lista 1 ha un vettore movimento che è minore di ±1/2 campioni di luma in
magnitudine (ed in alcuni altri casi), uno od entrambi i vettori predetti sono settati a zero, altrimenti
i vettori predetti della lista 0 ed 1 sono utilizzati per la moto-compensazione bi-predictive.
Nella modalità diretta temporale, invece, il decoder compie i seguenti step:

1) Trova l'immagine di riferimento della lista 0 per il macroblocco co-locato o la partizione


nell'immagine della lista 1. Questo riferimento di lista 0 diventa il riferimento di lista 0 del
macroblocco (o partizione) corrente.
2) Trova il vettore della lista 0, MV, per il macroblocco co-locato o partizione nell'immagine
della lista 1.
3) Il vettore di scala MV basato sull'ordine dell'immagine conta la “distanza” tra quella
corrente e le immagini della lista 1: questo è il nuovo vettore MV1 della lista 1.
4) Il vettore di scala MV basato sull'ordine dell'immagine conta la “distanza” tra le immagini
correnti e quelle della lista 0: questo è il nuovo vettore MV0 della lista 0.

Queste modalità sono modificate quando, ad esempio, i macroblocchi di riferimento di predizione


(o partizioni di essi) non sono disponibili o sono codificati intra.
Serviamoci, ancora una volta, di un esempio.
Supponiamo di trovarci nella situazione in cui il riferimento della lista 1 per il macroblocco corrente
si verifica ogni due immagini dopo il frame corrente.
Il macroblocco co-locato nel riferimento della lista 1 ha un vettore MV (+2.5, +5) che punta
all'immagine di riferimento della lista 0 che si verifica tre immagini prima dell'immagine corrente.
Il decoder calcola MV1 (-1, -2) e MV0 (+1.5, +3) che puntano alle immagini della lista 1 e 0
rispettivamente. Questi vettori sono derivati da MV ed hanno magnitudini proporzionali
al conteggio della distanza in ordine di immagini alle immagini di riferimento della lista 0 ed 1.
Per quanto concerne la predizione pesata, altro non è che un metodo di modifica (scaling)
dei campioni dei dati di predizione moto-compensata nei macroblocchi di slice P o B.
Ci sono tre tipi di predizione pesata in H.264:

1) Macroblocchi P slice: predizione pesata esplicita.


2) Macroblocchi B slice: predizione pesata esplicita.
3) Macroblocchi B slice: precisione pesata implicita.

Ogni campione di predizione pred0(i, j) o pred1(i, j) è scalato da un fattore di pesatura w0 o w1 prima


della predizione moto-compensata. Nelle predizioni pesate esplicite, i fattori di pesatura
sono determinati dall'encoder e trasmessi nello slice header.
Se viene utilizzata la predizione pesata implicita, w0 e w1 sono calcolati sulla base delle relative
posizioni temporali delle immagini di riferimento della lista 0 ed 1.
Viene applicato un fattore di pesatura più largo se l'immagine di riferimento è temporalmente vicina
all'immagine corrente e viene applicato un fattore di pesatura più stretto
se l'immagine di riferimento è temporalmente lontana dall'immagine corrente.
Un'applicazione della predizione pesata è di consentire il controllo esplicito o implicito dei relativi
contributi all'immagine di riferimento al processo di predizione moto-compensata. Ad esempio, la
predizione pesata può essere utile nella codifica di transizioni di dissolvenza
(quando una scena si dissolve in un'altra).
Come è stato già anticipato, con il profilo Main è anche possibile encodare video interlacciati.
La codifica efficiente di un video interlacciato richiede strumenti che sono ottimizzati
per la compressione di macroblocchi a field.
Se la codifica a field è supportata, il tipo di immagine (frame o field) è segnalato nell'header di ogni
slice. Nella modalità di codifica adattiva ai macroblocchi di frame/field (MB-AFF),
la scelta di codifica di field o frame può essere specificata a livello di macroblocchi.
In questa modalità, lo slice corrente è processato in unità di 16 campioni di luma (larghezza)
e 32 campioni di luma (altezza), ognuno dei quali è codificato come “coppia di macroblocchi”.
L'encoder può scegliere di encodare ogni coppia di macroblocchi come due macroblocchi “frame”,
oppure come due macroblocchi “field” e può selezionare la modalità di codifica ottimale
per ogni regione dell'immagine.
La codifica di uno slice o di una coppia di macroblocchi nella modalità field richiede
delle modifiche al numero di passi di encoding e decoding descritti in precedenza; ad esempio,
ogni field codificato è trattato come immagine di riferimento separata per la predizione di slice P
e B, la predizione delle modalità di codifica nei macroblocchi codificati intra ed i vettori movimento
nei macroblocchi codificati inter richiedono di essere modificati a seconda che i macroblocchi
adiacenti siano codificati in modalità frame o field e la scansione di riordinamento seguente
va a rimpiazzare quella a zig zag:

Quando nell'immagine appare il flag entropy_coding_mode settato su 1, viene utilizzato un sistema


di codifica aritmetica per encodare e decodificare gli elementi di sintassi dell'H.264. La codifica
aritmetica binaria adattiva al contesto (CABAC – Context based adaptive arithmetic coding)
raggiunge buone performance di compressione attraverso la selezione dei modelli di probabilità
per ogni elemento di sintassi secondo il contesto dell'elemento ed adattando le stime di probabilità
sulla base della statistica locale, nonché usando la codifica aritmetica invece di quella a lunghezza
variabile; tale codifica comporta 4 passi.

1) Binarizzazione. La CABAC utilizza la codifica aritmetica binaria, il che significa che solo le
decisioni binarie (1 o 0) vengono encodate. I simboli di valore non binario (tipo i
coefficienti di trasformata o i vettori movimento – generalmente ogni simbolo con più di due
possibili valori –) è “binarizzato” o convertito in codice binario prima della codifica
aritmetica. Questo processo è simile al processo di conversione di simboli di dato
in codice a lunghezza variabile, ma il codice binario è encodato a sua volta (dal codificatore
aritmetico) prima della trasmissione.

I passi 2, 3 e 4 sono ripetuti per ogni bit (o “bin”) dei simboli binarizzati:

2) Selezione del modello di contesto. Un modello di contesto è un modello probabile per uno o
più bin dei simboli binarizzati ed è scelto da una selezione di modelli disponibili a seconda
delle statistiche dei dati di simboli recentemente codificati. Il modello di contesto salva la
probabilità di ogni bin di essere 0 o 1.

3) Codifica aritmetica. Un codificatore aritmetico encoda ogni bin secondo il modello di


probabilità scelto e ci sono solo due sub-range per ogni bin e corrispondono a 0 ed 1.
4) Aggiornamento della probabilità. Il modello di contesto selezionato è aggiornato sulla base
del valore codificato attuale (ad esempio, se il valore di bin era 1, il primo contatore di
frequenza è incrementato).

Procederò ora con l'illustrazione di un esempio.


Supponiamo di voler codificare una differenza di vettore movimento in direzione x,
codificata per ogni partizione o partizione di sotto-macroblocco in un macroblocco intero: mvdx.

1) La binarizzazione del valore mvdx... mvdx è mappata alla seguente tabella di parola di codice
non unicamente decodificabile per |mvdx| < 9 (grandi valori di mvdx sono binarizzati
utilizzando la parola di codice Exp-Golomb).

Il primo bit della parola di codice binarizzata è bin 1, il secondo bit è bin 2 e così via.

2) Scelta di un modello di contesto per ogni bin. Uno dei tre modelli è selezionato per il bin 1,
basato sulla norma L1 di due valori mvdx precedentemente codificati, ek:

dove A e B sono i blocchi immediatamente a sinistra e sopra il blocco corrente.

Se ek è piccolo, c'è un'alta probabilità che l'MVD corrente abbia una piccola magnitudine e,
al contrario, se ek è grande è probabile che l'MVD corrente abbia una grande magnitudine.
Viene dunque selezionata una tabella di probabilità (modello di contesto)
ed i bin rimanenti sono codificati usando uno dei quattro ulteriori modelli di contesto:

3) Encoding di ogni bin. Il modello di contesto selezionato offre due stime di probabilità
(la probabilità che il bin contenga 1 e quella che il bin contenga 0) che determinano
due sub-range usati dal codificatore aritmetico per encodare il bin.
4) Aggiornamento dei modelli di contesto. Ad esempio, se per il bin 1 è selezionato il modello
di contesto 2 ed il valore del bin 1 è 0, il contatore di frequenza di zero è incrementato in
modo che, la prossima volta in cui questo modello è selezionato, la probabilità di uno 0 sarà
più alta. Quando il numero totale di ricorrenze al modello eccede il valore di threshold,
il contatore di frequenza per 0 ed 1 è ridimensionato e dà maggior importanza
alle osservazioni più recenti.

I modelli di contesto e gli schemi di binarizzazione per ogni elemento di sintassi sono definiti come
standard. Ci sono circa 400 modelli di contesto per i vari elementi di sintassi. All'inizio di ogni slice
codificato, i modelli di contesto sono inizializzati a seconda del valore iniziale del parametro
di quantizzazione QP (dato che ha un effetto significativo sulla probabilità di occorrenza dei vari
simboli). In aggiunta, per gli slice codificati P, SP e B, l'encoder può scegliere uno dei 3 set dei
parametri di inizializzazione del modello di contesto all'inizio di ogni slice per consentire l'adozione
di diversi tipi per contenuti video.
Il decoder aritmetico ha tre proprietà distinte:

1) La stima della probabilità è fatta da un processo di transizione tra 64 stati di probabilità


separati per l'ultimo simbolo meno probabile (LPS – Least Probable Symbol) delle due
decisioni binarie (ovvero 0 od 1).
2) Il range R rappresentante lo stato attuale del codificatore aritmetico è quantizzato in piccoli
range di valori predefiniti prima del calcolo del nuovo range ad ogni passo,
rendendo possibile il calcolo di nuovi range utilizzando una tabella di ricerca.
3) Per i simboli di dati con probabilità di distribuzione pressoché uniforme sono definiti un
encoding semplificato ed un processo di decoding
(in cui il la parte del modello di contesto è bypassata).

La definizione di processo di decoding è designata a facilitare le implementazioni di codifica


e decodifica aritmetica a bassa complessità e, soprattutto, la CABAC offre un'efficienza di codifica
migliore rispetto alla VLC.

– Il Profilo Extended

Il profilo Extended (conosciuto anche come X Profile nelle versioni precedenti dello standard
H.264) può essere particolarmente utile per applicativi come lo streaming video. Questo profile
include tutte le caratteristiche del profilo Baseline (cioè è un sovrainsieme del profilo Baseline,
a differenza del Main Profile), ma aggiunge i B slice, la predizione pesata ed altre caratteristiche
atte al supporto dello streaming tramite network, come lo streaming internet.
Gli slice SP ed SI facilitano il passaggio tra stream codificati in modo differente e la funzionalità
tipo VCR e gli slice di dati partizionati possono avere un buon impatto
negli ambienti di trasmissione più affini ad errori.
Procediamo dunque a parlare degli strumenti aggiuntivi del Profilo Extended
e cominciamo con gli slice SP ed SI.
Gli slice SP ed SI sono slice codificati in modo speciale che consentono uno switch efficiente tra gli
stream video ed un efficiente accesso random per i decoder video. Un requisito comunemente
richiesto in un contesto di streaming è la possibilità da parte del decoder di switchare tra tanti
stream encodati. Ad esempio, lo stesso materiale video è codificato varie volte a bitrate diversi per
la trasmissione tramite internet ed il decoder cerca di decodificare lo stream con il bitrate più alto
che può ricevere, ma potrebbe essere necessario switchare automaticamente ad uno stream a bitrate
più basso per motivi relativi alla linea od altro.
Facciamo un esempio pratico: un decoder sta decodificando uno stream A e vuole switchare alla
decodifica dello steam B. Per semplicità, supponiamo che ogni frame sia encodato come un singolo
slice e predetto da una referenza (il frame decodificato precedentemente).

Dopo la decodifica degli slice P A0 ed A1, il decoder vuole switchare dallo stream A allo stream B
e decodificare B2, B3 e così via. Se tutti gli slice nello stream B sono codificati come slice P,
allora il decoder non avrà il frame di riferimento precedentemente codificato corretto
per decodificare B2, proprio perché stava codificando lo stream A prima, ma B2 è predetto
dall'immagine precedentemente decodificata B1, che, chiaramente, non esiste nello stream A. Una
soluzione sarebbe quella di codificare il frame B2 come slice I; codificando senza predizione da altri
frame, può essere decodificato indipendentemente dai frame precedenti nello stream B ed il decoder
può per tanto switchare tra lo stream A e B. Dunque, quello che può essere fatto è inserire degli
slice I (detti anche “punti di switch” ad intervalli regolari nella sequenza codificata in modo da
consentire al decoder il passaggio tra uno stream ed un altro. Ad ogni modo, uno slice I contiene
molti più dati di uno slice P ed il risultato altro non è che un picco nel bitrate ad intervalli regolari
(cioè ad ogni “punto di switch”); ecco che entrano in gioco gli slice SP! Gli slice SP sono fatti per
supportare lo switch tra sequenze codificate in modo simile (ad esempio, la stessa source encodata
a bitrate differenti per uno streaming) senza aumentare il bitrate per colpa degli slice I.
Al punto di switch (frame 2 in ogni sequenza), ci sono tre slice SP, ognuno dei quali è codificato
utilizzando una predizione moto-compensata (così da renderli più efficienti degli slice I).
Lo slice SP A2 può essere decodificato utilizzando l'immagine di riferimento A1 e lo slice SP B2 può
essere decodificato utilizzando l'immagine di riferimento B1. La chiave per il processo di switching
è lo slice SP AB2 (conosciuto come “slice di switching SP”), creato in modo che possa essere
decodificato utilizzando l'immagine di riferimento moto-compensata A1 per produrre il frame
decodificato B2 (ovvero l'output del decoder B2 è identico sia decodificando B1 seguito da B2,
sia decodificando A1 seguito da AB2). È richiesto uno slice SP extra ad ogni punto di switch
(difatti, per switchare nell'altra direzione, sarebbe richiesto un altro slice SP, BA2),
ma è sempre più efficiente che encodare i frame A2 e B2 come slice I.
Di seguito vengono mostrati gli step impiegati quando un decoder deve switchare da uno stream A
ad uno stream B:

L'immagine sottostante mostra un diagramma semplificato del processo d'encoding per uno slice SP
A2, prodotto dalla sottrazione di una versione moto-compensata di A'1 (frame A1 decodificato)
dal frame A2 e codificando poi il residuo:

A differenza dei “normali” slice P, la sottrazione viene effettuata nel dominio di trasformata
(dopo la trasformata del blocco). Lo slice SP B2 è encodato nello stesso modo:

Un decoder che ha decodificato precedentemente il frame A1 può decodificare lo slice SP A2,


come mostrato nell'immagine sottostante:

Come ho già detto, questi diagrammi sono semplificati, difatti, in realtà, sono richiesti ulteriori passi
di quantizzazione e rescaling per evitare il mismatch tra encoder e decoder.
Di seguito viene mostrato l'encoding dello slice SP AB2 (sempre in maniera semplificata):
Il frame B2 (il frame a cui stiamo switchando) è trasformato e la predizione moto-compensata
è formata da A'1 (il frame decodificato dal quale stiamo switchando).
Il blocco MC in questo diagramma cerca di trovare il match migliore per ogni macroblocco di frame
B2 utilizzando l'immagine decodificata A1 come riferimento. La predizione moto-compensata è
trasformata, poi sottratta da B2 trasformato. Il residuo (dopo la sottrazione) è quantizzato, encodato
ed infine trasmesso.
Un decoder che ha precedentemente decodificato A'1 può decodificare lo slice SP AB2
per produrre B'2:

A'1 è moto-compensato (utilizzando il dato di vettore movimento encodato come parte di AB2),
trasformato ed aggiunto al residuo decodificato e scalato (inversamente quantizzato),
poi il risultato è inversamente trasformato per produrre B'2.
Se gli stream A e B sono versioni della stessa sequenza d'origine codificati a bitrate differenti,
la predizione moto-compensata di B2 da A'1 (slice SP AB2) dovrebbe essere efficiente.
I risultati mostrano che utilizzando gli slice SP per switchare tra diverse versioni della stessa
sequenza è significativamente più efficiente che inserire slice I nei punti di switch.
Un altro applicativo degli slice SP è di garantire accessi random tipo funzionalità VCR.
Ad esempio, uno slice SP ed un slice di switching SP sono posizionati al frame 10.

Un decoder può fare una predizione in avanti da A0 direttamente ad A10 decodificando A0


e decodificando lo slice SP di switching A0-10 per produrre la predizione A10 da A0.
Il profilo Extended supporta un altro tipo di slice di switching, lo slice SI. Il suo utilizzo è simile
allo slice di switching SP, eccetto per il fatto che la predizione è formata utilizzando modalità di
predizione intra da 4x4 per i campioni precedentemente decodificati del frame ricostruito.
Questa modalità di slice può essere utilizzata, per esempio, per switchare da una sequenza ad una
sequenza completamente differente (nel qual caso non sarà efficiente utilizzare la predizione moto-
compensata perché non c'è correlazione tra le due sequenze).
Il dato codificato che genera uno slice è collocato in tre partizioni di dati distinte: A, B e C,
ognuna delle quali contiene un sottoinsieme dello slice codificato. La partizione A contiene l'header
dello slice ed i dati di header per ogni macroblocco nello slice. La partizione B contiene i dati
residui codificati per ogni slice di macroblocchi intra ed SI. La partizione C contiene dati residui
codificati per i macroblocchi codificati inter (in avanti e bi-direzionali). Ogni partizione può essere
inserita in una unità NAL separata e può essere trasportata separatamente.
Se i dati della partizione A sono persi, è molto difficile o addirittura impossibile ricostruire lo slice,
visto che la partizione A è molto sensibile agli errori di trasmissione. Le partizioni B e C possono
(con molta attenzione alla scelta dei parametri di codifica) essere fatti per essere codificabili
indipendentemente e, di conseguenza, un decoder sarà in grado di decodificare (per esempio) solo A
e B o solo A e C, consentendo una migliore flessibilità in un ambiente soggetto ad errori.

– Trasporto dell'H.264

Dunque, come accennato, una partizione può essere inserita in una unità NAL.
Una sequenza video codificata H.264 consiste in una serie di unità NAL, ognuna contenente un
RBSP. Di seguito sono elencati i tipi di RBSP:

– Parameter Set: parametri globali per una sequenza, come la dimensione dell'immagine, il
formato video, la mappa di allocazione del macroblocco ecc.
– Informazioni supplementari: messaggi supplementari che non sono essenziali per la corretta
decodifica della sequenza video.
– Delimitatore d'immagine: bordi tra le immagini video. Se non presente, il decoder deduce il
bordo sulla base del numero di frame contenuti all'interno di ogni slice header.
– Slice codificato: header e dati per uno slice; questa unità RBSP contiene i dati video
codificati attuali.
– Dato di partizione (A, B, C): tre unità; la partizione A contiene il dato di header per tutti i
macroblocchi nello slice, la partizione B contiene i dati codificati intra e la partizione C
contiene i dati codificati inter.
– Fine della sequenza: indica che la prossima immagine (nell'ordine di riproduzione) è
un'immagine IDR. (Non è essenziale per la corretta decodifica della sequenza).
– End of stream: indica che non ci sono altre immagini nel bit-stream.
(Non è essenziale per la corretta decodifica della sequenza).
– Dato filler: contiene dati fittizi che possono essere utilizzati per aumentare il numero di byte
nella sequenza. (Non è essenziale per la corretta decodifica della sequenza).

Gli slice codificati (inclusi gli slice di dati partizionati e gli slice IDR) e l'RBSP di fine sequenza
sono codificati come unità NAL VCL mentre tutti gli altri elementi sono solo unità NAL.
Un esempio di sequenza tipica di unità RBSP è mostrata dalla seguente immagine:

Ognuna di queste unità è trasmessa in un'unità NAL separata. L'header di unità NAL (un byte)
segnala il tipo di unità RBSP ed i dati RBSP compongono il resto dell'unità NAL.
L'H.264 introduce inoltre il concetto di “parameter sets”, ognuno dei quali contiene informazioni
che possono essere applicate ad un grande numero di immagini codificate.
Un “sequence parameter set” contiene parametri che possono essere applicati ad una sequenza
video completa (un set di immagini codificate consecutive).
I paramentri nel “sequence parameter set” includono un identificativo “seq_parameter_set_id”,
limitato ai numeri dei frame ed al conteggio dell'ordine delle immagini, al numero di immagini
di riferimento che può essere usato in decodifica (inclusi i frame di riferimento a breve e lungo
termine), all'altezza ed alla larghezza dell'immagine decodificata, nonché alla scelta di codifica
progressiva (frame) o interlacciata (field).
Il “picture parameter set” contiene i parametri che sono applicati ad una o più immagini
decodificate all'interno di una sequenza.
Ogni “picture parameter set” include, tra gli altri parametri, un identificativo
“pic_parameter_set_id”, un seq_parameter_set_id, un flag per scegliere la codifica entropica VLC
o CABAC, il numero di gruppi di slice in uso (ed una definizione del tipo di slice nella group map),
il numero di immagini di riferimento nella lista 0 e nella lista 1 che può essere utilizzato
per la predizione, i parametri di quantizzazione iniziale ed un flag indicante se i parametri di default
del filtro di deblocking devono essere modificati o meno.
Generalmente, uno o più “sequence parameter set” e “picture parameter set” sono inviati al decoder
prima della decodifica degli slice header e dei dati slice. Uno slice header codificato si riferisce
ad un pic_parameter_set_id e questo “attiva” quel “picture parameter set” particolare.
Il “picture parameter set” attivato rimane attivo finché non viene attivato un altro “picture parameter
set” dal riferimento di un altro slice header. In modo analogo, il “picture parameter set” si riferisce
al seq_parameter_set_id, che “attiva” quel “sequence parameter set”. Il set attivato rimate in vigore
(ovvero i suoi parametri sono applicati a tutte le immagini codificate consecutive)
finché non viene attivato un altro “sequence parameter set”.
Il meccanismo dei “parameter set” consente all'encoder di segnalare sequenze importanti
che cambiano non frequentemente ed i “picture parameters”,
separatamente dagli slice codificati stessi.
I “parameter set” possono essere inviati prima degli slice che li riferiscono,
o da un altro meccanismo di trasporto (ad esempio, in un canale di trasmissione affidabile
od addirittura “cablato” nell'implentazione del decoder). Ogni slice codificato
può richiamare l'immagine rilevante ed i “sequence parameters” utilizzando un singolo VLC
(pic_parameters_set_id) nello slice header.
Il metodo di trasmissione delle unità NAL non è specificato nello standard, ma sono fatte alcune
distinzioni tra i meccanismi di trasporto basate sui pacchetti (network basati sui pacchetti)
e le trasmissioni in uno stream di dati continuo (ambienti a commutazione di circuito).
In un network basato sui pacchetti, ogni unità NAL può essere trasmessa in un pacchetto separato
e deve essere organizzata nell'ordine corretto di sequenza prima della decodifica.
Negli ambienti a commutazione di circuito, un prefisso di inizio codice (un codice delimitante
unicamente identificabile) è inserito prima di ogni unità NAL per creare un byte stream
prima della trasmissione. Questo fa sì che il decoder possa cercare lo stream
per trovare il prefisso di inizio codice che identifica l'inizio di un'unità NAL.
In un applicativo comune, il video codificato è richiesto di essere trasmesso o salvato con tracce
audio a lui associate ed informazioni aggiuntive. È possibile usare un range di meccanismo
di trasporto per farlo, come l'RTP (Real Time Protocol) e l'UDP (User Datagram Protocol).
Molti altri applicativi richiedono il salvataggio di video ed audio multiplexed
ed informazioni aggiuntive (come il playback dei DVD).

– Comparison tra H.264 8bit e H.264 10bit

Come già detto precedentemente quando sono stati analizzati i vari profile,
l'H.264 è anche in grado di encodare video a 10bit.
In alcuni applicativi professionali, è possibile avere source a 10bit
ed è pertanto possibile lavorare con tali video.
Il motivo dietro all'utilizzo del 10bit è che, tendenzialmente, è possibile avere banding nei file video
codificati dalla stessa source ad 8bit, rispetto a quelli a 10bit.
Per mostrare un esempio pratico, sono state riportate due immagini;
tali immagini sono state estratte da due video encodati dalla stessa source.
I parametri di encoding sono stati lasciati invariati, ma la prima immagine è stata estratta dalla
sequenza video codificata con l'encoder H.264 di riferimento a 8bit,
mentre la seconda è stata encodata utilizzando l'encoder H.264 di riferimento a 10bit.
È possibile notare come, nella prima immagine, sono stati introdotti artefatti di banding
che sono molto visibili nel cielo:
Encodando la stessa sequenza video dalla stessa source ed estraendo lo stesso frame dal flusso
video codificato a 10bit con gli stessi settaggi, è possibile notare come tale sgradevole effetto sia
scomparso:

Dagli esempi codificati è possibile inoltre notare come le performance di codifica siano aumentate:
maggiore qualità allo stesso bitrate. Il guadagno medio oscilla dal 5 al 20% per gli encoding fatti
sulle source prese in esame. Questo perché quando il video viene encodato in 10bit, vengono
utilizzati gli strumenti di codifica 10bit ed il processo di codifica è eseguito con accuratezza a 10bit,
contro la normale accuratezza a 8bit. In questo modo, c'è un minor errore di troncamento,
soprattutto durante la l'importante fase della moto-compensazione.
Dunque, l'efficienza degli strumenti di compressione aumenta e, di conseguenza, c'è minor bisogno
di quantizzare per raggiungere un dato bitrate.
– Valutazioni finali:

L'H.264 offre un meccanismo di codifica video ottimizzato per l'efficienza di compressione e punta
a venire incontro alla richiesta di applicativi comuni e pratici di comunicazione multimediale.
Grazie alle sue funzionalità, alle sue performance ed ai numerosi settaggi possibili, è stato
ampiamente diffuso negli anni precedenti. La possibilità di lavorare su materiale progressivo ed
interlacciato, a 8 e 10bit ed in 4:2:0, 4:2:2 e 4:4:4, nonché gli anni di sviluppo che ha alle spalle ed i
profile adatti ad innumerevoli utilizzi lo hanno reso un codec stabile, maturo, versatile ed affidabile.

3.6.0) Introduzione all'HEVC – H.265

L'ITU-T Video Coding Experts Group (VCEG) cominciò a portare avanti degli studi su una
tecnologia in grado di consentire la creazione di un nuovo standard di video compressione (o, per
meglio dire, un miglioramento dello standard H.264/MPEG-4 Part 10 AVC). Furono presto proposte
varie tecniche di miglioramento dello standard H.264 e vennero considerati due approcci
fondamentali per la standardizzazione della nuova tecnologia di compressione: creare un nuovo
standard o creare un'estensione per lo standard H.264. Il progetto venne chiamato H.265 o H.NGVC
(Next-Generation Video Coding) ed era portato avanti dal VCEG. I requisiti preliminari per
l'NGVC erano di ottenere una riduzione del bitrate del 50% rispetto all'H.264 (High profile) allo
stesso livello di qualità soggettiva d'immagine, con una complessità computazionale che va da metà
a 3 volte quella dell'High profile. Allo stesso tempo, l'ISO/IEC Moving Picture Experts Group
(MPEG) iniziò un progetto simile, chiamato “High performance video coding”. L'obiettivo
dell'ISO/IEC MPEG era di ottenere una riduzione del bitrate del 50%, ma, dopo mesi e mesi di
sviluppo, erano riusciti ad ottenere solamente il 20% di bitrate in meno rispetto all'H.264 AVC High
Profile. Visti i risultati, dunque, l'ISO/IEC MPEG decise di unire le forze con il VCEG nella
standardizzazione del nuovo codec. Vennero fatte varie proposte (27 in totale) che vennero proposte
al primo meeting tra MPEG ed il VCEG. Durante tale meeting, vennero valutate tutte le proposte
mostrate ed alcune di esse riuscirono ad ottenere una riduzione del bitrate del 50% rispetto all'H.264
(durante i numerosi test proposti) al costo di un aumento del doppio o di 10 volte nella complessità
computazionale, ed alcune proposte raggiunsero una buona qualità soggettiva e risultati di bitrate
con minore complessità computazionale rispetto a quella dell'H.264 High Profile.
Visti gli ottimi risultati ottenuti, la collaborazione venne consolidata e nacque così l'HEVC
(High Efficiency Video Coding).

3.6.1) Una trasformata adattiva per la codifica video migliorata


basata sull'H.264/AVC

La trasformata spaziale è sempre stato uno strumento di codifica di base negli standard di codifica
video sviluppati in passato. In molti casi è stata adottata la DCT in modo che sia l'encoder che il
decoder sapessero, fin dall'inizio, quali funzioni di trasformata di base devono essere usate.
Il lato negativo di questo tipo di approccio è che le funzioni di trasformata di base non tengono
conto del contenuto specifico e, di conseguenza, non si “adattano” ad esso,
riducendo una potenziale maggiore efficienza di codifica. Ad ogni modo,
c'è da dire che le funzioni di trasformata di base non devono essere computate né trasmesse.
Comunque, una soluzione alternativa è di adottare una trasformata adattiva le cui funzioni di base
cambiano a seconda del contenuto.
Una soluzione che segue questo principio è l'adozione della DCT o della MKLT, ovvero una KLT
modificata (trasformata di Karhunen–Loève), a seconda del blocco da encodare.
Questa soluzione consente l'adattamento al contenuto dei blocchi senza dover trasmettere le
funzioni di base KLT dato che sono equalmente stimate sia dall'encoder che dal decoder.
Questo metodo è stato integrato nell'H.264 mod per migliorarne le capacità rispetto all'H.264
normale.
Richiamando quanto detto ad inizio tesi (quando ho analizzato le varie trasformate), la trasformata
di Karhunen-Loève è la trasformata ottimale in termini di compressione. Ad ogni modo, la maggior
parte degli standard di codifica video fanno uso della DCT per rappresentare le informazioni video
nel dominio delle frequenze. Questa scelta è data dal fatto che la DCT, a differenza della KLT, non
richiede computazione, codifica e trasmissione all'encoder delle sue funzioni di base per ogni
blocco (ovvero, è indipendente dai dati) e può raggiungere un'efficienza di compressione pressoché
ottimale per i segnali altamente correlati. Difatti, il vantaggio in fase di compressione ottenuto dalla
KLT rispetto alla DCT è virtualmente perso dai bit extra richiesti per rappresentare le sue funzioni
di base. La proposta fu quindi di utilizzare una trasformata adattiva che consentisse una selezione
dinamica tra la DCT e la MKLT (Karhunen-Loève modificata) a seconda del contenuto dei blocchi.
Questa soluzione non richiede la codifica e la trasmissione delle funzioni di base della MKLT;
al contrario, queste vengono stimate dall'encoder e dal decoder utilizzando la stessa tecnica ed
assicurando così le stesse funzioni di trasformata di base per entrambi. In questo modo, è possibile
sfruttare l'ottimo funzionamento della KLT, in particolare per i blocchi che sono più difficili
da codificare utilizzando la DCT, come, ad esempio, i blocchi con bordi diagonali.
Per quanto riguarda la tecnica basata sulla KLT proposta, è possibile applicarla solo sui blocchi
soggetti ad errore di predizione in quanto tale trasformata può portare benefici in termini
di compressione solamente per i blocchi codificati inter.
Questa limitazione è imposta dalle caratteristiche della tecnica stessa che descriverò di seguito.

3.6.2) Architettura

Come già detto sopra, tale soluzione era stata designata per essere integrata nello standard H.264
per portare benefici nell'efficienza di compressione. In tale contesto, l'architettura principale è
praticamente la stessa dell'architettura dell'H.264, con l'eccezione dei moduli di trasformata in
avanti ed inversa. Ad ogni modo, la sintassi di bit-stream, la semantica ed il comportamento in fase
di decodifica cambiano e la compatibilità con l'H.264 normale viene meno. L'architettura generale
viene riportata nella figura sottostante:

Il processo di encoding si divide in:


– Divisione in macroblocchi: per prima cosa, il video in input è diviso in macroblocchi da
16x16, così come nell'H.264 normale. Per la soluzione di codifica proposta, sono state
utilizzate le estensioni FRExt, implicando che anche i blocchi da 8x8 sono disponibili.
Ad ogni modo, in questo caso, solo i blocchi da 8x8 vengono utilizzati per l'operazione
di trasformata, ma gli autori non hanno mai fornito alcuna spiegazione a riguardo.
– Trasformata: per trasformare ogni blocco in input, l'encoder decide se utilizzare la DCT
dello standard H.264 oppure la MKLT. Poi, tale scelta viene segnalata al decoder utilizzando
solo 1 bit per ogni blocco codificato. (Nella prossima sezione verrà spiegata in dettaglio).
– Quantizzazione: i coefficienti di trasformata (DCT o MKLT) per ogni blocco sono poi
quantizzati nello stesso modo dell'H.264 standard.
– Codifica entropica: infine, i coefficienti quantizzati sono codificati entropicamente
utilizzando la CAVLC. Per i blocchi DCT trasformati, viene utilizzato l'ordine di scansione
dell'H.264 normale (ovvero la scansione a zig-zag e la scansione alternata),
mentre per i blocchi MKLT i coefficienti sono messi (da quello con varianza più alta
a quello con varianza più bassa) in quattro blocchi da 4x4 che sono poi passati all'encoder
entropico.

Per quanto riguarda il decoder, l'unica differenza rispetto all'H.264 normale è relativa
al modulo di trasformata, che verrà descritto nella prossima sezione. La scelta tra la DCT inversa
e la MKLT inversa è fatta secondo le informazioni incluse nel bit-stream dall'encoder per ogni dato.

3.6.3) Dettagli della Trasformata Adattiva

Come accennato sopra, la soluzione che venne proposta faceva uso di una delle due trasformate: la
DCT o la MKLT. Questa trasformata adattiva è applicabile solamente ai blocchi codificati inter,
dove solo l'errore di predizione è trasformato e quantizzato.
Di seguito viene rappresentata l'architettura per la trasformata in avanti:

Come mostrato in figura, la trasformata adattiva in avanti consiste in pratica nella computazione
della DCT in avanti e della MKLT in avanti, seguite dalla selezione della trasformata
che offre le migliori performance. Per computare la MKLT, l'errore di predizione dev'essere stimato
e le funzioni di base computate sulla base dell'errore di predizione stimato,
come verrà descritto di seguito.
Per quanto riguarda la decodifica, la trasformata adattiva inversa consiste nella computazione della
DCT inversa o della MKLT inversa, a seconda di quale trasformata era stata selezionata
in fase di encoding. Ancora una volta, per computare la MKLT, l'errore di predizione dev'essere
stimato e le funzioni di base MKLT computate sulla base dell'errore di predizione stimato,
come verrà descritto in seguito.
Mentre la DCT è esattamente la stessa di quella usata nell'H.264 per i blocchi 8x8, l'MKLT,
per quanto simile alla KLT standard, ha alcune particolarità che verranno spiegate di seguito.
Dunque, la prossima sezione è dedicata a tale trasformata.
Dall'osservazione delle architetture di trasformata adattiva in avanti ed inversa è possibile
concludere che il processo della MKLT (Modified Karhunen-Loève Transform) include 3 moduli
principali (notare i blocchi colorati nelle immagini soprastanti): stima dell'errore di predizione,
computazione delle funzioni di base MKLT e computazione della MKLT (sia la KLT in avanti che
la KLT inversa).
I tre moduli sono descritti di seguito:

1) Modulo di stima dell'errore di predizione:

L'errore di predizione è la differenza tra il blocco originale ed il blocco MCP (Motion Compensated
Prediction) che in H.264 è codificato utilizzando vettori movimento associati con uno o più
immagini di riferimento. In questo contesto, l'unica possibilità di evitare la trasmissione delle
funzioni di base al decoder è di stimare l'errore di predizione. Per poterlo fare, è presupposto che
l'errore di predizione sia causato dagli errori nel processo di moto-compensazione, in particolare:

– errori di interpolazione: nel processo di moto-compensazione, alcuni errori possono


verificarsi quando vengono interpolati i pixel delle immagini di riferimento per
un'accuratezza di un quarto di pixel.

– Predizione dei bordi imprecisa: nei blocchi con forti bordi diagonali, i vettori movimento
potrebbero non essere predetti con piena accuratezza, causando un piccolo shift
nella locazione dei bordi tra l'originale ed il blocco MCP.

Seguendo queste supposizioni, è stata proposta la stima dell'errore di predizione simulando


tali condizioni. Questo è fatto sottraendo versioni spostate e ruotate del blocco MCP dal blocco
MCP stesso che, in questo caso, gioca il ruolo di “dato originale”.
L'utilizzo del blocco MCP per questa “funzione” è abbastanza “naturale” in quanto è l'unica parte di
informazione che è disponibile contemporaneamente sia all'encoder che al decoder. Per semplificare
questa operazione, l'immagine sottostante rappresenta un blocco originale da 8x8 – che viene
chiamato (a) –, il suo blocco MCP corrispondente – che viene chiamato (b) –
ed il blocco di errore di predizione – che viene chiamato (c).

Il blocco MCP è poi spostato verticalmente di -0.25 pixel e ruotato di -0.5° (a) e, per completare
l'operazione, il blocco MCP spostato e ruotato è poi sottratto al blocco MCP (b):

Malgrado il cambio di segno quando è comparato con l'errore di predizione attuale (prima
immagine, blocco “c”), la correlazione tra i pixel nella stima dell'errore di predizione (seconda
immagine, blocco “b”) sembra simile alla correlazione inter-pixel nel “vero” errore di predizione.
Questo può essere utile dato che le funzioni di base KLT sono computate dalla matrice di
covarianza del blocco (di errore) di input. Per consentire lo sfruttamento della proprietà dell'errore
di predizione descritto sopra nelle varie direzioni, sono stati proposti il seguente spostamento
e la seguente rotazione del blocco MCP per la stima dell'errore di predizione:

– Shift (spostamento): il blocco MCP è spostato orizzontalmente e verticalmente di:

– Rotazione: il blocco MCP è ruotato di:

Ad ogni modo, non è mai stato rivelato il criterio utilizzato per definire i parametri di spostamento
e rotazione massimi (rispettivamente 0.5 pixel e 0.5°).
La combinazione di tutti i 5 parametri di spostamento sulle direzioni orizzontale e verticale
dà vita a 25 blocchi MCP spostati (5x5 = 25).
Questi blocchi MCP spostati possono essere ruotati con 3 parametri di rotazione differenti
(-0.5°, 0.0° e 0.5°), dando vita ad un set di 75 blocchi MCP spostati e ruotati (25x3 = 75).
Poi, la differenza tra il blocco MCP attuale ed il set di blocchi MCP spostati e ruotati
è computato in modo da ottenere un set di 75 blocchi di errore di predizione stimato.
Consideriamo come esempio la figura riportata di seguito nella quale viene rappresentato un set
di 25 blocchi di errore di predizione stimato (in questo caso sono rappresentati solo i risultati
per la rotazione -0.5°):
Con un set di blocchi di errore di predizione stimato è poi possibile computare le funzioni di base
della MKLT.

2) Modalità di computazione delle funzioni di base MKLT

Come detto precedentemente, la KLT è una trasformata unitaria ed ortogonale, tuttavia, a differenza
della DCT, non è separabile. Inoltre, per trasformare un blocco bidimensionale, è necessario prima
convertire tale blocco in una colonna o in una riga di vettori. Poi, la matrice di covarianza del
vettore dev'essere computata per determinare, dopo i suoi autovettori, quali colonne rappresentano
le funzioni di base della trasformata. L'MKLT che venne proposta comprende le caratteristiche della
KLT descritte sopra, tuttavia, in questo caso, ci sono più blocchi di input rappresentanti un set di
blocchi di errore di predizione stimato (le “vere” predizioni non sono disponibili al decoder).
Per determinare la matrice di covarianza di questo set, è necessario definire la covarianza tra ogni
posizione di pixel. Inoltre, la covarianza tra un pixel in posizioni (u, v) ed un pixel in posizione
(r, s) per un set di blocchi nxn è dato da:

Tornando ai tre esempi esposti sopra, è possibile determinare la matrice di covarianza per un set di
blocchi di predizione stimato utilizzando l'equazione appena proposta; il risultato è questo:
La riga evidenziata mostra la covarianza del pixel in riga 3, colonna 0
(considerata qui come il pixel di riferimento) con i pixel in tutte le altre posizioni.
Riportando questa riga alla sua forma originale bidimensionale, si ha il blocco dei valori di
covarianza mostrato dall'immagine sottostante, dove l'asterisco rosso segnala la posizione
del pixel di riferimento:

Osservando l'immagine soprastante è possibile concludere che la covarianza con il pixel di


riferimento è più alta per i pixel in direzione del bordo, se è una covarianza positiva (nella stessa
locazione del pixel di riferimento) o negativa (in un altro bordo del blocco).
Con la matrice di covarianza per un particolare set di blocchi di errore di predizione stimato
disponibili, è poi possibile determinare gli autovettori e gli autovalori associati:

dove phi è la matrice di autovettori e lambda è la matrice diagonale di autovalori della matrice
di covarianza Σ.
Successivamente, la matrice transposta della matrice di autovettori phi è computata,
risultando in funzioni di base MKLT.
Per l'esempio di sopra, le funzioni di base sono illustrate nell'immagine seguente:
Nella figura soprastante il set di funzioni di base è arrangiato in un ordine di scansione raster
orizzontale dov'è possibile vedere che le prime funzioni di base (in alto a sinistra) mostrano una
similitudine soggettiva all'errore di predizione attuale.

3) modulo di computazione MKLT

Dopo la determinazione delle funzioni di base MKLT, è poi attualmente possibile computare la
MKLT sia per l'encoder che per il decoder. Inoltre, la MKLT in avanti e la MKLT inversa
sono date da:

dove x è l'errore di predizione attuale, TMKLT sono le funzioni di base MKLT, CMKLT sono i coefficienti
MKLT, x' è l'errore di predizione ricostruito ed i coefficienti MKLT quantizzati sono dati da:

Tornando all'esempio precedente, i coefficienti MKLT del blocco di errore di predizione attuale
sono mostrati di seguito con i coefficienti DCT per lo stesso blocco:

È doveroso ricordare inoltre che questo blocco ha un forte bordo diagonale per il quale la DCT
(col fatto che è separabile) non è molto adatta.
Da tale immagine è possibile vedere non solo l'alta compattezza di energia raggiunta dalla MKLT
(con quasi tutta l'energia concentrata nei coefficienti in alto a sinistra),
ma è anche possibile compararla con le performance corrispondenti della DCT per lo stesso blocco,
che distribuisce la stessa energia di segnale in input in un maggiore numero di coefficienti di
trasformata. Un'analisi più approfondita può essere fatta per la scansione per ogni trasformata.
Considerando una scansione a zig zag per i coefficienti DCT ed ordinando i coefficienti MKLT
diminuendo la varianza è possibile tracciare i coefficienti mostrati nella figura soprastante
in termini di ampiezza e posizione di scansione:
Il grafico rappresentato qua sopra mostra che, per questo esempio, l'MKLT non solo comprime
l'energia del segnale in entrata in meno coefficienti, ma questi coefficienti sono anche i primi ad
essere scansionati! Per quanto riguarda la DCT, invece, l'energia del segnale in input è distribuita
in un maggior numero di coefficienti ed, inoltre, la scansione a zig zag sembra non posizionarli
efficientemente per riduzione di ampiezza. Di conseguenza, dovrebbe essere possibile codificare
entropicamente i coefficienti MKLT con meno bit di quelli richiesti per codificare
i coefficienti DCT.

3.6.4) Valutazione delle prestazioni

Per valutare le performance della soluzione di trasformata adattiva che venne proposta
(cioè la selezione dinamica tra MKLT e DCT) questo nuovo metodo venne integrato nell'H.264.
Il test sperimentale venne condotto con sequenze video di risoluzioni QCIF e CIF a 30fps
per le seguenti sequenze video: Foreman, Mobile, Garden ed Husky.
I test sono stati fatti encodando 50 frame di ogni sequenza video e misurando il PSNR risultante
come:

dove MSE è l'errore quadrato medio tra i frame del video originale e quelli del video ricostruito.
Per valutare i benefici della soluzione proposta (H.264 mod AT), le sue performance vennero
comparate a quelle dell'H.264 standard (il profilo preciso non è specificato). Le sequenze video
codificate utilizzano un pattern regolare di un frame I seguito da frame P per ogni GOP
(Group of Picture). Le sequenze video codificate sono state selezionate come particolarmente
difficili da codificare con la DCT ed hanno un alto dettaglio ed/o blocchi con alta varianza e bordi
diagonali. I grafici riportati di seguito mostrano le performance di distorsione per l'H.264 mod (AT)
proposto e l'H.264 normale (standard):

I grafici soprastanti mostrano un guadagno medio PSNR di 0.5 dB per la soluzione proposta (H.264
mod AT) contro l'H.264 standard, tuttavia, a causa dell'alto costo computazionale e di un guadagno
non rilevante in termini di risparmio di bitrate che si verificava solo ed esclusivamente in maniera
percepibile su sequenze prese ad hoc e che non portava benefici tangibili negli esempi di vita reale
nonostante un alto costo computazionale, l'esperimento dell'H.264 modificato fece vertere verso una
strategia diversa per l'H.265, ovvero l'utilizzo della DCT e della DST (Discrete Sine Transform).

3.7) HEVC – H.265

Dato che tutte le proposte presentate all'HEVC “Call for Proposal” facevano uso dell'architettura
di codifica di base utilizzata negli standard di codifica video precedenti (in particolar modo
dell'H.264), l'architettura HEVC è basata anch'essa sulle modalità di codifica intra ed inter
utilizzando una predizione moto-compensata e la codifica basata su trasformata.
L'architettura HEVC di base è presentata nell'immagine sottostante:
Considerando che la differenza fondamentale tra l'H.265 e l'H.264 è finalizzata alle risoluzioni cui
sono destinati, le proposte inviate si concentravano sullo sfruttamento dell'alta ridondanza spaziale e
temporale disponibile sui contenuti ad alta risoluzione ed UHD. Tali sforzi diedero vita a vari nuovi
strumenti di codifica che cambiarono alcuni dei principali moduli architetturali, come evidenziato
nella figura soprastante. Questi nuovi strumenti di codifica sono descritti di seguito, con l'eccezione
di quelli relativi alla codifica tramite trasformata che sono spiegati in modo più dettagliato
successivamente.

– Picture partitioning

Per prima cosa, lo standard HEVC introduce un nuovo schema di partizionamento delle immagini
basato su una nuova definizione dell'unità di codifica e non più i soliti macroblocchi.
Il concetto di macroblocchi precedente è sostituito da una struttura più flessibile: il CTB
(Coding Tree Block). Con questa struttura, ogni CTB può avere una grandezza diversa (da 8x8 a
128x128, utilizzando sempre potenze di due) e può essere ricorsivamente diviso
in un partizionamento a “Quad tree”.
La grandezza massima di un CTB e la profondità massima del partizionamento quad tree
sono definiti dal level della sequenza video.
L'unità di codifica più grande è denominata LCTB (Largest Coding Tree Block) e quella più piccola
è denominata SCTB (Smallest Coding Tree Block).
Ogni immagine è divisa in LCTB non sovrapposti ed ogni CTB è caratterizzato dalla sua grandezza
LCTB e la sua profondità gerarchica in relazione col suo LCTB corrispondente.
Per comprendere meglio questa struttura, l'immagine qui sotto rappresenta un esempio dove la
grandezza del LCTB è di 128 e la profondità gerarchica massima è di 5.
Come mostrato dalla figura soprastante, la struttura ricorsiva è rappresentata da una serie di
“split flag”. Se lo split flag è uguale ad 1, allora il CTB corrente è diviso (“splittato”) in quattro
CTB indipendenti, caratterizzati da una profondità incrementata e da metà grandezza del CTB
precedente. Il partizionamento dell'immagine è fermato quando lo split flag è uguale a zero o
quando viene raggiunta la profondità massima, raggiungendo l'SCTB.
Con questa nuova struttura di partizionamento è possibile codificare grandi aree omogenee con
blocchi di codifica più grandi dei precedenti macroblocchi da 16x16 utilizzati dall'H.264,
sfruttando in modo migliore la ridondanza spaziale.
Inoltre, questa struttura di codifica consente una scelta più flessibile delle grandezze dei blocchi
per una codifica più efficiente di vari contenuti, puntando a più applicativi e device.
Quando il processo di divisione (“splitting”) è completato, le “leaf nodes” del tree gerarchico CTB
diventano PU (Prediction Unit) e possono essere splittate nei seguenti modi:

– Intra PU: i PU intra non sono splittati o sono splittati in 4 partizioni uguali.

– Inter PU: i PU inter possono avere 4 split simmetrici, 4 split asimmetrici oppure possono
essere splittati con una modalità di partizionamento geometrica. In quest'ultima modalità,
il blocco è diviso in due regioni da una retta caratterizzata da due parametri: la distanza tra
la linea di partizione e l'origine del blocco (p), che è misurata da una linea perpendicolare
alla linea di partizione, e l'angolo sostenuto da questa linea perpendicolare e l'asse x θ.

Un esempio è rappresentato dalla figura sottostante:


Oltre ai CTB ed ai PU, l'HEVC introduce anche i TU (Transform Unit). Queste unità sono definite
per la trasformazione e la quantizzazione e possono essere larghi tanto quanto la grandezza della
“foglia” (leaf) CTB corrispondente, ovvero il PU corrispondente.
Il partizionamento dei TU è rappresentato anche dai quad trees,
con la loro grandezza massima e la profondità gerarchica segnalate nel bitstream.
Le dimensioni di blocco di trasformata sono obbligate dalle dimensioni di trasformata
massima e minima, rispettivamente 4x4 e 64x64.
Queste caratteristiche sono affrontate nel dettaglio più avanti,
quando parlerò del processo di trasformata e quantizzazione.

– Intra prediction

Per i blocchi codificati intra, l'HEVC supporta fino a 33 direzioni di predizione spaziale per blocchi
da 8x8 fino a 64x64; questo viene fatto tramite la modalità di predizione planare.
Per i blocchi da 4x4, vengono utilizzate le 9 modalità di predizione già definite nell'H.264.

– Moto-compensazione

Per consentire lo sfruttamento dei vettori movimento con accuratezza a quarto di pixel,
i frame di riferimento devono essere upsampled ed essere in grado di procurare un'interpolazione
di accuratezza a quarto di pixel.
Nell'H.264, per tale interpolazione, viene utilizzato da prima un filtro di Wiener fissato a 6 passi,
seguito da una combinazione bilineare di interi e valori di metà pixel.
Con l'HEVC, è possibile utilizzare un filtro di interpolazione a 12 passi basato sulla DCT
per ottenere la stessa interpolazione con accuratezza a quarto di pixel.
In questo modo, è necessaria una sola procedura di filtraggio, consentendo una semplificazione
dell'implementazione ed una riduzione della complessità del processo di filtraggio.

– Filtro di deblocking e filtro “in loop”

Il filtro di deblocking dell'H.264 è stato adattato nell'HEVC per supportare le nuove dimensioni
dei blocchi (che sono più grandi).
Inoltre, è stato aggiunto un filtro di Wiener simmetrico per consentire una riduzione
della distorzione di quantizzazione nei blocchi ricostruiti.
– Codifica entropica

L'HEVC offre due tipi di metodo di codifica entropica:


– codifica entropica a bassa complessità: sono designate 10 tabelle VLC pre-determinate per
diverse distribuzioni di probabilità; ogni elemento di sintassi utilizza una delle 10 tabelle di
riferimento. Per la codifica entropica dei coefficienti di trasformata, viene utilizzato un
metodo CAVLC migliorato.
– Codifica entropica ad alta complessità: viene utilizzata una variazione della soluzione
CABAC definita nell'H.264. Le basi di questo codec sono simili, ma è introdotta la
parallelizzazione della codifica e della decodifica entropica.

Queste sono le principali innovazioni introdotte dall'HEVC.


Nella sezione successiva, vengono descritte in modo più esaustivo i processi di trasformata
e quantizzazione.

– Transformata e Quantizzazione:

Una trasformata più grande può portare alti benefici in termini di compattezza di energia e ridurre
l'errore di quantizzazione per grandi aree omogenee. Le sequenze in HD tendono ad avere più
correlazione spaziale, il che significa parti di immagine più grandi. L'H.265 utilizza
un'approssimazione a precisione finita di due Trasformate Discrete del Coseno di dimensioni che
vanno da 8x8 a 32x32 ed una Trasformata Discreta del Seno alternativa di grandezza 4x4 che viene
usata per la predizione intra del luma dei blocchi residui. Lo standard specifica le matrici per le
trasformate di ogni dimensione di blocco (4x4, 8x8, 16x16, 32x32) e la matrice per i blocchi di
predizione intra del luma della trasformata alternativa che è una trasformata intera basata sulla DST.
Ogni coefficiente di matrice è rappresentato con 8 bit (incluso il bit del segno) e viene scalato ad un
fattore di 2^6+M/2 rispetto alla DCT ortonormale. Le matrici sono fatte per preservare le proprietà
di (anti) simmetria che permettono di ricavare la metà destra della matrice dalla metà sinistra. Non
solo, i coefficienti delle matrici più piccole (4x4, 8x8, 16x16) possono essere derivati dalla matrice
32x32 ed anche la matrice di trasformata inversa è definita come trasposta delle matrici di
trasformata in avanti.
L'immagine di sopra mostra la parte sinistra della matrice di trasformata in avanti da 32x32 e le aree
evidenziate mostrano le matrici da 16x16, 8x8 e 4x4 che possono essere derivate dalla matrice
32x32. I coefficienti di trasformata sono ottenuti applicando una trasformata monodimensionale a 2
passi per le righe e per le colonne che comporta la moltiplicazione di matrice dei coefficienti
predetti risultati con le loro rispettive matrici. Infine, i coefficienti di trasformata sono sottoposti a
quantizzazione usando una scala Q-Step. Il processo inverso è la de-quantizzazione seguita da
un'altra trasformata a 2 passi che è la moltiplicazione della trasposta delle matrici menzionate
prima.

Procedimento di trasformata in avanti ed inversa

Come detto prima, le matrici vengono scalate di 2^6+M/2 per cui, per preservare la norma dello del
blocco residuo è necessario uno scaling aggiuntivo nella forma ST1, ST2, SIT1, SIT2. Questi fattori sono
delineati nello standard e sono fatti per essere applicabili usando le operazioni di shift logico. Sia B
il bit depth, M = Log2 N e sia N la grandezza di trasformata, allora i fattori di scaling sono:

Un processo simile viene applicato per la DST che fornisce una riduzione del bitrate dell'1% nelle
immagini intra. La matrice DST è:
– Profile e Comparison

Per quanto riguarda il profile, l'HEVC vanta vari profile, dedicati a diversi bit-depth,
campionamenti di colore e, più in generale, ad un diverso utilizzo.

1) Main profile: il main profile consente un bit-depth di 8 bit per campione


con un campionamento a 4:2:0, che è il più comune dal punto di vista dei consumer device.

2) Main 10: il main 10 consente un bit-depth di 8 o 10bit per campione con un campionamento
di 4:2:0. I decoder HEVC conformi al profile Main 10 devono essere in grado di
decodificare bit-stream fatti con il profilo Main. Un bit-depth maggiore consente un maggior
numero di colori (come già detto sopra). 8 bit per campione consentono 16.78 milioni di
colori, mentre 10 bit per campione consentono 1.07 miliardi di colori e, come visto sopra,
così facendo è possibile evitare il banding. Il profile Main 10 consente una qualità video
migliore visto che può codificare più colori e, inoltre, se la source non è nativa a 10bit,
questa può essere portata e codificata a 10bit dal codec.

Main 10 vs Main profile:


Visto che le migliori comparison si fanno sul campo, è stata presa una sequenza video di risoluzione
3840x2160 (UHD 4K) nativa a 10bit ed è stata encodata prima con il Main 10 e poi col semplice
Main profile. Il video encodato col Main 10 è, chiaramente, rimasto a 10bit, mentre quello encodato
col Main profile è stato scalato ad 8 bit. Nella sequenza video presa in esame, il profile Main 10 è
riuscito ad ottenere una riduzione del bitrate del 5% per la codifica dei frame inter, comparato al
Main profile. È stato inoltre proposto il Main 10 profile per portare un'alta qualità video per le
applicazioni consumer e tale profilo è attualmente in grado di supportare la matrice di colore
Rec.2020, specifica per i video in UHD che è in grado di rappresentare fedelmente i colori senza
provocare banding.

3) Main Still Picture profile: il Main Still Picture profile consente l'encoding di una singola
immagine fissa con le stesse limitazioni del Main profile. Come sottoinsieme del Main
profile, il Main Still Picture profile consente un bit depth di 8 bit per campione
ed il campionamento 4:2:0.

Main Still Profile (HEVC) vs JPEG:


Visto che stiamo parlando di codifica delle immagini fisse, è alquanto interessante fare una
comparazione tra l'HEVC con un codec di codifica delle immagini lossy;
per tale scopo, ho scelto come “avversario iniziale” il JPEG.
Dal test effettuato, è curioso sapere come la riduzione del bitrate è stata del 56.0%
rispetto a quella del JPEG.

Main Still Profile (HEVC) vs JPEG2000:


Come secondo avversario, ho deciso di prendere il JPEG2000 in quanto, come già visto, utilizza un
metodo di codifica tramite trasformata non a blocchi proprio per evitare gli artefatti di blocking.
Il fatto che utilizzi la trasformata di Wavelet e non la DCT, lo rendeva appetibile per un confronto.
Il risultato del test è che l'HEVC ha una riduzione del bitrate del 30.0% rispetto al JPEG2000.

Main Still Profile (HEVC) vs H.264:


Per quanto riguarda l'ultimo test, ho deciso di comparare l'HEVC con l'H.264 ed i risultati ottenuti
sono una riduzione del bitrate del 15.8% da parte dell'HEVC nei confronti dell'H.264.
4) Monochrome profile: Il profile monochrome consente un bit-depth di 8 bit per campione e
supporta il campionamento 4:0:0.
5) Monochrome 12: il monochrome 12 consente un bit-depth da 8 a 12 bit per campione e
supporta il campionamento 4:0:0.
6) Monochrome 16: il monochrome 16 consente un bit-depth da 8 a 16 bit per campione e
supporta il campionamento 4:0:0. I decoder HEVC conformi al profile monochrome 16
devono essere in grado di riprodurre anche il Monochrome ed il Monochrome 12.

7) Main 12: il Main 12 consente un bit-depth da 8 a 12 bit per campione e supporta il


campionamento 4:0:0 ed il 4:2:0. I decoder HEVC conformi al profile Main 12 devono
essere in grado di riprodurre anche il Monochrome, il Monochrome 12, il Main ed il
Main10.
8) Main 4:2:2 10: il Main 4:2:2 10 consente un bit-depth da 8 a 10 bit per campione e supporta
il campionamento 4:0:0, 4:2:0 e 4:2:2. I decoder HEVC conformi al profile Main 4:2:2 10
devono essere in grado di riprodurre anche il Monochrome, il Main ed il Main10.
9) Main 4:2:2 12: il Main 4:2:2 12 consente un bit-depth da 8 a 12 bit per campione e supporta
il campionamento 4:0:0, 4:2:0 e 4:2:2. I decoder HEVC conformi al profile Main 4:2:2 12
devono essere in grado di riprodurre anche il Monochrome, il Monochrome 12, il Main, il
Main10, il Main 12 ed il Main 4:2:2 10.
10) Main 4:4:4: il Main 4:4:4 consente un bit-depth di 8 bit per campione e supporta il
campionamento a 4:0:0, 4:2:0, 4:2:2 e 4:4:4. I decoder HEVC conformi al profile Main
4:4:4 devono essere in grado di riprodurre anche il Monochrome ed il Main.
11) Main 4:4:4 10: il Main 4:4:4 10 consente un bit-depth da 8 a 10 bit per campione e supporta
il campionamento a 4:0:0, 4:2:0, 4:2:2 e 4:4:4. I decoder HEVC conformi al profile Main
4:4:4 10 devono essere in grado di riprodurre anche il Monochrome, il Main, il Main 10,
il Main 4:2:2 10 ed il Main 4:4:4.
12) Main 4:4:4 12: il Main 4:4:4 12 consente un bit-depth da 8 a 12 bit per campione e supporta
il campionamento a 4:0:0, 4:2:0, 4:2:2 e 4:4:4. I decoder HEVC conformi al profile Main
4:4:4 12 devono essere in grado di riprodurre anche il Monochrome, il Monochrome 12, il
Main, il Main 10, il Main 12, il Main 4:2:2 10, il Main 4:2:2 12, il Main 4:4:4 ed il
Main 4:4:4 10.
13) Main 4:4:4 16 intra: il Main 4:4:4 16 intra consente un bit-depth da 8 a 16 bit per campione
e supporta il campionamento a 4:0:0, 4:2:0, 4:2:2 e 4:4:4. I decoder HEVC conformi al
profile Main 4:4:4 16 intra devono essere in grado di riprodurre anche il Monochrome Intra,
Monochrome 12 Intra, Monochrome 16 Intra, Main Intra, Main 10 Intra, Main 12 Intra,
Main 4:2:2 10 Intra, Main 4:2:2 12 Intra, Main 4:4:4 Intra ed il Main 4:4:4 10 Intra.
14) High Throughput 4:4:4 16 Intra: l'High Throughput 4:4:4 16 Intra consente un bit-depth da 8
a 16 bit per campione e supporta il campionamento a 4:0:0, 4:2:0, 4:2:2 e 4:4:4. Questo
profile ha un HbrFactor 12 volte più grande degli altri profile dell'HEVC, il che consente di
avere un bitrate massimo 12 volte più grande del profile Main 4:4:4 16 intra. Tale profile è
creato esclusivamente per la creazione di contenuti professionali e non è richiesto ai decoder
di supportare altri profile.
15) Main 4:4:4 Still Picture: il Main 4:4:4 Still Picture consente l'encoding di una singola
immagine con le stesse limitazioni del profile Main 4:4:4; come sottoinsieme del profile
Main 4:4:4, il Main 4:4:4 Still Picture consente un bit-depth di 8 bit per campione e supporta
il campionamento a 4:0:0, 4:2:0, 4:2:2 e 4:4:4.
16) Main 4:4:4 16 Still Picture: il Main 4:4:4 16 Still Picture consente l'encoding di una singola
immagine con le stesse restrizioni del profile Main 4:4:4 16 Intra; come sottoinsieme del
profile Main 4:4:4 16 Intra, il Main 4:4:4 16 Still Picture consente un bit-depth da 8 a 16 bit
per campione e supporta il campionamento a 4:0:0, 4:2:0, 4:2:2 e 4:4:4.
17) Scalable Main: il profile Scalable Main è conforme al Main profile.
18) Scalable Main10: il profile Scalable Main 10 è conforme al Main10 profile.
19) Multiview Main: il profile Multiview Main è conforme al Main profile.
20) 3D Main: il 3D Main è conforme al Main profile e permette la riproduzione 3D.
21) Screen Extended Main: lo Screen Extended Main consente un bit-depth di 8 bit per
campione e supporta il campionamento a 4:0:0 e 4:2:0. I decoder HEVC conformi allo
Screen Extended Main devono essere in grado di riprodurre anche il Monochrome ed il
Main profile.
22) Screen Extended Main 10: lo Screen Extended Main 10 consente un bit-depth da 8 a 10 bit
per campione e supporta il campionamento a 4:0:0 e 4:2:0. I decoder HEVC conformi allo
Screen Extended Main 10 profile devono essere in grado di riprodurre anche il
Monochrome, il Main, il Main 10 e lo Screen Extended Main profile.
23) Screen Extended Main 4:4:4: lo Screen Extended Main 4:4:4 consente un bit-depth di 8 bit
per campione e supporta il campionamento a 4:0:0, 4:2:0, 4:2:2 e 4:4:4. I decoder HEVC
conformi allo Screen Extended Main 4:4:4 devono essere in grado di riprodurre anche il
Monochrome, il Main, il Main 4:4:4 e lo Screen Extended Main profile.
24) Screen Extended Main 4:4:4 10: lo Screen Extended Main 4:4:4 10 consente un bit-depth da
8 a 10 bit per campione e supporta il campionamento a 4:0:0, 4:2:0, 4:2:2 e 4:4:4. I decoder
HEVC conformi allo Screen Extended Main 10 devono essere in grado di riprodurre anche il
Monochrome, il Main, il Main 10, il Main 4:2:2 10, il Main 4:4:4, il Main 4:4:4 10, lo
Screen Extended Main, lo Screen Extended Main 10 e lo Screen Extended Main 4:4:4
profile.

– Level e Tier

Rispetto all'H.264, con l'HEVC non si hanno solo i level, ma anche i tier.
Per quanto riguarda i level, esattamente come per H.264, servono a “formalizzare” il bit-stream
facendo sì che i produttori possano implementare applicazioni in grado di riprodurre in modo ideale
tutti i video appartenenti alla fascia considerata “supportata” e tagliando fuori tutti quelli non
supportati, onde evitare possibili incopatibilità, blocchi e quant'altro; in questo contesto entrano in
gioco i tier. In pratica, invece di avere semplicemente un level numerato (1, 2, 2.1, 3, 3.1, 4, 4.1, 5,
5.1, 5.2, 6, 6.1, 6.2) si hanno anche due tier (Main ed High) che ne specificano il bitrate massimo.
L'esigenza di aggiungere i tier nasce dal fatto che alcuni decoder potrebbero essere in grado di
riprodurre un certo numero di kbit/s e, in fase di encoding, se si supera il numero di kbit/s massimo
per un certo livello, si è “costretti” a passare al livello successivo, rischiando di perdere la
compatibilità con alcuni hardware. Grazie ai tier, invece, è possibile rimanere nello stesso level
(invece di passare al level successivo). Di seguito sono riportati i tier ed i level:
Per quanto riguarda lo standard, è doveroso ricordare che è stato recentemente approvato il nuovo
standard bluray disk 4K (UHD).
Secondo il nuovo standard, i video verranno encodati utilizzando l'HEVC a risoluzione UHD
con bit-depth di 10bit, campionamento a 4:4:4 ed una nuova matrice di colore, la BT.2020.

– La nuova matrice di colore BT.2020

Con il bisogno di rappresentare contenuti in UHD, così come c'è stata l'evoluzione nel codec,
c'è stata una evoluzione anche nella color matrix. È doveroso dire che, comunque, anche l'H.264 è
attualmente in grado di supportare la nuova matrice di colore e che, nell'ultima versione rilasciata,
è in grado di riprodurla. Ad ogni modo, la BT.2020 specifica due risoluzioni: 3840x2160 4K UHD e
la 7680x4320 8K (16:9). Per quanto riguarda gli fps, invece, sono possibili 120 fps, 119.88 fps, 100
fps, 60 fps, 59.94 fps, 50 fps, 30 fps, 29.97 fps, 25 fps, 24 fps, 23.976 fps ed è consentita la sola
scansione progressiva. Per quanto riguarda il bit-depth, si possono avere sia 10 che 12 bit, con
livelli differenti: per il campionamento a 10bit, il livello del nero è definito come codice 64 ed il
picco nominale è definito dal codice 940. I codici 0-3 e1020-1023 sono utilizzati per i riferimenti,
i codici da 4 a 63 contengono le informazioni sotto al livello del nero, mentre i codici da 941 a 1019
contengono le informazioni sopra al picco nominale. Per il campionamento a 12 bit, il livello del
nero è definito come codice 256 ed il picco nominale è definito dal codice 3760. I codici da 0-15 e
4080-4095 sono utilizzati per i riferimenti, i codici da 16 a 255 contengono le informazioni sotto al
livello del nero, mentre i codici da 3761 a 4079 contengono le informazioni sopra al
picco nominale.La BT.2020 è in grado di riprodurre colori che non possono essere riprodotti dalla
BT.709 e la lunghezza d'onda dei colori primari della BT.2020 è di 630 nm per il rosso, 532 nm per
il verde e 467 nm per il blu. Inoltre, per la BT.2020, è stato deciso di utilizzare colori reali (invece
di colori immaginari) in modo da poter riprodurre la BT.2020 a display senza bisogno di
conversione. Inoltre, la BT.2020 supporta l'RGB e l'YCbCr con campionamento a 4:4:4, 4:2:2 e
4:2:0.La BT.2020 definisce una funzione di trasferimento non lineare che può essere usata per la
correzione di gamma con RGB ed YCbCr. L'RGB può essere utilizzato quando è richiesta la miglior
qualità possibile, mentre l'YCbCr può essere utilizzato quando si punta alla compatibilità con le
SDTV ed HDTV e le componenti di luma e chroma nell'YCbCr sono calcolate dall'RGB già
sottoposto a correzione di gamma. La BT.2020 definisce inoltre una versione linearmente encodata
dell'YCbCr (chiamata YcCbcCrc) e le cui componenti sono calcolate dall'RGB lineare
e poi sottoposte a correzione di gamma.Dunque, per quanto riguarda la versione a 10bit della
BT.2020, viene utilizzata la stessa funzione utilizzata dalla BT.709, mentre per la versione a 12bit,
la BT.2020 ci sono dei cambiamenti nella funzione di trasferimento non lineare dato che il punto di
minimo in un range di intensità di luce da 0 a 1 dove comincia la funzione di trasferimento è portato
da 0.018 a 0.0181. La funzione di trasferimento non lineare è lineare vicino a 0 e poi trasferisce ad
una funzione di potenza il resto del range di intensità di luce:

dove E è il segnale proporzionale all'intensità di luce, E ' è il segnale non lineare risultante ed alpha
e beta equivalgono a 1.099 e 0.018 per 10bit e 1.0993 e 0.0181 per 12 bit.

– Conclusioni

L'HEVC risulta essere un nuovo utile codec video in grado di ottenere i traguardi designati
e supporta altissime risoluzioni in modo migliore rispetto al suo predecessore, l'H.264.
3.8) VVC – H.266

- Introduzione e somiglianze con l’H.265

Nonostante l’HEVC H.265 sia ormai maturo e con anni di sviluppo alle spalle, l’avvento dell’8K ha
mostrato le sue limitazioni ed è stato dunque necessario procedere allo sviluppo di un nuovo,
migliore codec. Visto il successo della collaborazione per l’HEVC H.265 da parte del VCEG (Video
Coding Experts Group) e dell’MPEG (Moving Picture Experts Group), tale rapporto è stato
consolidato negli anni successivi al suo sviluppo ed i due gruppi si sono uniti ancora una volta per
lavorare ad un codec capace di sorpassare l’HEVC H.265 e di poter gestire l’8K senza un aumento
sostanziale di bitrate; nasce così il VVC (Versatile Video Coding) H.266. Il nuovo codec nasce dalla
base dell’H.265 ma introduce nuove tecniche di encoding ed ottimizzazioni; ad esempio, è stata
migliorata l’accuratezza della predizione nella motocompensazione e sono stati eliminati i concetti
di Prediction Unit (PU) e Transform Unit (TU). La differenza sostanziale tra l’H.265 e l’H.266 è
che il primo usa la struttura di partizione Quad-Tree (QT) mentre il secondo usa la struttura di
partizione MTT che include la QT. Ancora una volta, l’obiettivo del nuovo codec è di avere il 50%
di riduzione del bitrate al pari della stessa qualità soggettiva, ma, come accade sempre, al decrescere
del bitrate, aumenta la complessità computazionale. Nell’H.265 ogni frame è diviso in vari CTU
(Coding Tree Unit).
Un CTU contiene un blocco di luma e due blocchi di chroma con le grandezze corrispondenti. La
massima grandezza consentita per il blocco di luma è 128x128 ed il massimo consentito per il
blocco di chroma è 64x64. Inoltre, solo il tipo di partizione QT è consentito nell’H.265, il che limita
la forma dei sotto-CU a dei quadrati. Nell’H.266 abbiamo invece la struttura di partizione MTT che
include 5 strutture: BT_H (Horizontal Binary Tree Partition), BT_V (Vertical Binary Tree Partition),
TT_H (Horizontal Ternary Tree Partition), TT_V (Vertical Ternary Tree Partition) e QT. Tra esse, il
rapporto di grandezza delle tre parti nella struttura di partizione TT è 1:2:1. La struttura di
partizione MTT consente ai CU di essere partizionati in maniera asimmetrica. In teoria, la larghezza
e l’altezza dei CU può essere combinata da 4 a 128 in maniera arbitraria, tuttavia, secondo le
restrizioni di configurazione, un CTU da 128x128 pixel sarà diviso in 4 sotto-CU dal QT
direttamente. Quando il sotto-CU è diviso ulteriormente, viene considerata – a seconda delle
caratteristiche della texture – una struttura di partizione QT o MTT. In pratica, il range di larghezza
ed altezza dei CU è limitato tra 4 e 64. Inoltre, c’è una regola di partizionamento che non può essere
ignorata; senza considerare la profondità dei livelli, ciascuno dei 5 tipi di partizionamento può
essere eseguito sotto un nodo QT, ma solo le modalità di partizionamento TT e BT possono essere
eseguite sotto al nodo MTT.

Schema della modalità di partizionamento CU e relativo diagramma


Il cerchio nero nella figura rappresenta il CTU mentre i cerchi blu rappresentano i nodi radice. La
grandezza minima consentita da un nodo foglia QT è 4x4, la grandezza massima consentita per i
nodi radice TT è 32x32, la massima profondità TT è 3 livelli e la grandezza minima consentita per
un nodo foglia BT è 4x4. L’introduzione di queste modalità di partizionamento CU più flessibili ha
portato ad alcuni problemi di partizionamento ridondante. Per risolvere questo problema, l’H.266
limita la partizione dei CU sulla base del livello di profondità, della grandezza e dei CU vicini.
D’altra parte, queste regole di partizionamento sono adottare per fare in modo che il CU sia diviso
in maniera appropriata. Le due situazioni più comuni sono:

- Il CU corrente è diviso dal TT_V


- Il CU corrente è diviso dal BT_V

Nel primo caso, l’area nel mezzo delle tre parti dopo il partizionamento non può più essere divisa
dal BT_V, altrimenti sarebbe equivalente a due partizioni BT_V. Lo stesso vale per la partizione
orizzontale.

Nel secondo caso, se abbiamo il CU diviso dal BT_V e la parte sinistra è divisa dal BT_H, allora la
sua parte destra non può più essere divisa dal BT_V, altrimenti sarebbe equivalente ad una
partizione QT (e lo stesso vale per la partizione orizzontale).

Metodi di partizionamento non validi

L’introduzione della struttura di partizionamento MTT migliora l’accuratezza della codifica, ma


sono necessari più processi di RDO (Rate Distortion Optimization) per determinare il metodo di
partizionamento ottimale. Il tempo richiesto dall’RDO rappresenta una porzione sostanziale
dell’intero tempo di encoding, il che risulta in un aumento significativo nel tempo di codifica e nella
complessità.
Come nell’H.265, dunque, anche l’H.266 è basato su un’architettura di encoding basata sulla
divisione in blocchi e, come il precedente codec, utilizza la predizione tramite moto-compensazione
per individurare frame I, P e B ed unisce la codifica con trasformata alla codifica entropica.
Diagramma generale della codifica in H.266 VVC

La struttura di partizionamento dell’immagine divide il video in ingresso in blocchi chiamati CTU


(Coding Tree Units). Un CTU è diviso usando un quadtree con una struttura ad albero multi-tipo in
CU (Coding Units), con una foglia CU che definisce una regione che condivide lo stesso metodo di
predizione (ad esempio intra od inter). Dunque, abbiamo detto che le immagini sono divise in una
sequenza di CTU (Coding Tree Unit) con un concetto che abbiamo già visto sia sopra che quando
abbiamo parlato dell’H.265. Per un’immagine che ha 3 sample array, un CTU consiste in un blocco
di sample luma NxN assieme ai due blocchi corrispondenti di sample del chroma. La grandezza
massima del blocco di luma in un CTU è 128x128, ma la grandezza massima del luma è 64x64.

Esempio di una immagine divisa in CTU

- Partizionamento dell’immagine in CUT, sotto-immagini, slice, tile


Un’immagine è divisa in una o più tile in righe e colonne. Una “tile” è una sequenza di CTU che
copre una regione rettangolare dell’immagine. Uno “slice” consiste invece in un numero intero di
tile complete o un numero intero di righe consecutive complete di CTU all’interno di una tile di
un’immagine. Sono supportate due modalità di “slice”, ovvero la modalità raster-scan slice e la
modalità a slice rettangolare. Nella prima modalità, quella raster-scan slice, uno slice contiene una
sequenza di tile complete in un raster scan dell’immagine. Nella seconda modalità, quella a slice
rettangolare, uno slice contiene o un numero di tile complete che formano collettivamente una
regione rettangolare dell’immagine, oppure un numero di righe consecutive complete di CTU di una
tile che formano collettivamente una regione rettangolare dell’immagine. Le tile all’interno di uno
slice rettangolare sono scansionati in una scansione raster ordinata all’interno della regione
rettangolare corrispondente a quello slice. Una sotto-immagine contiene uno o più slice che coprono
collettivamente una regione rettangolare dell’immagine. Per visualizzare la cosa, facciamo finta di
avere un partizionamento di un’immagine di tipo raster-scan slice in cui l’immagine è divisa in 12
tile e 3 raster-scan slice:

Supponiamo ora invece di avere un’immagine con partizionamento di tipo slice rettangolare in cui
l’immagine è divisa in 24 tile (6 colonne tile e 4 righe tile) e 9 slice rettangolari, allora avremo:
Esempio di un’immagine partizionata in tile e slice rettangolari

Supponiamo ancora di avere un’immagine partizionata in tile e slice rettangolari, ma in cui


l’immagine è divisa in 4 tile (2 tile colonne e 2 tile righe) e 4 slice rettangolari, in questo caso:

Esempio di un’immagine partizionata in 4 tile e 4 slice rettangolari

Se invece abbiamo un partizionamento di sotto-immagine in cui un’immagine viene partizionata in


18 tile, 12 a sinistra, ognuna che copre uno slice di 4 per 4 CTU e 6 tile a destra, ognuna che copre 2
slice messe in verticale da 2 per 2 CTU, per un totale di 24 slice e 24 sotto-immagini di dimensioni
diversa (ogni slice è una sotto-immagine), allora:
Esempio di un’immagine partizionata in 28 sotto-immagini

- Partizionamento dei CTU usando una struttura ad albero

Nell’H.265, come abbiamo visto, un CTU è diviso in CU usando una struttura ad alberto
quaternaria denotata come CT (Coding Tree) per l’adattamento alle varie caratteristiche locali. La
decisione di codificare un’area di immagine usando la predizione inter-immagine (temporale) o
intra-immagine (spaziale) è fatta al livello della foglia CU. Ogni foglia CU può essere divisa
ulteriormente in uno, due o quattro, a seconda del tipo di divisione PU. All’interno di un PU viene
applicato lo stesso processo di predizione e l’informazione rilevante è trasmessa al decoder sulla
base del PU. Dopo aver ottenuto il blocco residuo applicando il processo di predizione basato sul
tipo di divisione PU, una foglia CU può essere partizionata in TU (Transform Unit) a seconda di
un’altra struttura a foglia quaternaria simile al Coding Tree del CU. Una delle caratteristiche
principali della struttura dell’H.265 è che ci sono i concetti di partizione multipla, inclusi i CU, i PU
ed i TU. Nell’H.266, il concetto di unità di partizione multipla è stato rimpiazzato da un Quad Tree
con un NMTT (Nested Multi Type Tree) ed una struttura di segmentazione a divisione ternaria.
Detto altrimenti, il concetto di separazione dei CU, PU, TU non esiste più tranne per i CU che sono
troppo grandi per la grandezza di trasformata massima in cui il nuovo metodo è più flessibile e
supporta più forme di partizione CU. Nella struttura CT (Coding Tree) un CU può avere sia una
forma quadrata che rettangolare. Un CTU (Coding Tree Unit) viene prima partizionato da una
struttura ad albero quaternaria (Quadtree), poi i nodi della foglia dell’albero vengono divisi
ulteriormente da una struttura ad albero multi-tipo. Ci sono 4 tipi di divisione in una struttura ad
albero multi-tipo: la divisione binaria verticale SPLIT_BT_VER, la divisione binaria orizzontale
SPLIT_BT_HOR, la divisione ternaria verticale SPLIT_TT_VER e la divisione ternaria orizzontale
SPLIT_TT_HOR. I nodi della foglia dell’albero multi-tipo sono chiamati CU (Coding Unit) e, a
meno che il CU sia troppo grande per la lunghezza massima di trasformata, questa segmentazione
viene utilizzata per la predizione e per la trasformata senza ulteriori partizionamenti. Questo
significa che, il più delle volte, il CU, PU e TU hanno la stessa grandezza nella struttura di codifica
a blocchi Quadtree con NMTT (Nested Multi Type Tree).

Modalità di divisione dell’MTT (Multi Type Tree)

Il meccanismo di segnalazione dell’informazione del partizionamento e di come avviene la


divisione nei Quadtree con struttura NMTT (Nested Multi Type Tree) è rappresentato nel seguente
schema:

Flag di divisione (Split) nei Quadtree


con struttura di codifica ad albero NMTT (Nested Multi Type Tree)

Un CTU (Coding Tree Unit) è trattato come la radice di un albero quaternario ed è prima
partizionato da una struttura ad albero quaternaria. Ogni nodo foglia dell’albero quaternario
(quando è abbastanza grande) viene poi partizionato ulteriormente da una struttura ad albero multi-
type, ovvero MTT (Multi Type Tree). Nella struttura MTT (Multi Type Tree), c’è un primo flag
MTT Split che indica se il nodo viene partizionato ulteriormente e, se lo è, c’è un secondo flag Split
MTT Verticale che indica la direzione in cui è stato diviso (splittato) ed infine abbiamo un terzo flag
Split MTT Binario che indica se la divisione (split) è una divisione binaria (Split Binario) o ternaria
(Split Ternario). A seconda dei valori del Flag Split MTT Verticale e Flag Split MTT Binario, viene
derivata la modalità di divisione MTT (Multi Type Tree):

Modalità di Divisione MTT Flag Split MTT Verticale Flag Split MTT Binario
Split TT_HOR 0 0
Split BT_HOR 0 1
Split TT_VER 1 0
Split BT_VER 1 1

La rappresentazione grafica di un CTU diviso in più CU con un Quadtree ed una struttura di


codifica a blocchi NMTT (Nested Multi Type Tree) è data da:

Esempio di Quadtree con struttura di codifica a blocchi NMTT (Nested Multi Type Tree)
Le parti in nero della rappresentazione di sopra rappresentano il partizionamento Quadtree mentre
le parti in grigio rappresentano il partizionamento MTT (Multi Type Tree). Il partizionamento
Quadtree con NMTT (Nested Multi Type Tree) fornisce una struttura di codifica ad albero formata
da CU che si adatta al contenuto. La grandezza del CU può essere tanto larga quanto il CTU, oppure
più piccola fino ad un minimo di 4x4 unità di sample di luma. Nel caso del 4:2:0, la grandezza
massima del CB del chroma è 64x64 e la grandezza minima è 16 sample di chroma. La massima
grandezza di trasformata è però 64x64 per il luma e 32x32 per il luma, quindi quando il CB è più
grande della massima grandezza di trasformata, questo viene diviso in orizzontale e/o verticale per
poter raggiungere le dimensioni necessarie.
Per lo schema di codifica NMTT (Nested Multi Type Tree) vengono definiti (e specificati) i
seguenti elementi:

1) Grandezza del CTU

La grandezza del nodo radice di un albero quaternario.

2) La grandezza minima del QT

La grandezza minima consentita del nodo foglia dell’albero quaternario.

3) La grandezza massima del BT

La grandezza massima consentita del nodo radice dell’albero binario.

4) La grandezza massima del TT

La grandezza massima consentita dal nodo radice dell’albero ternario.

5) Grandezza minima del BT

La grandezza minima consentita dal nodo foglia dell’albero binario.

6) La grandezza minima del TT

La grandezza massima consentita dal nodo radice dell’albero ternario.

7) La profondità massima dell’MTT

La profondità massima consentita a livello gerarchico di un MTT (Multi Type Tree) che deriva da
una foglia Quadtree.

Facciamo un esempio di struttura di codifica ad albero Quadtree con NMTT (Nested Multi Type
Tree) e supponiamo che la grandezza del CTU sia 128x128 sample di luma con due blocchi di
chroma da 64x64 per il 4:2:0. La grandezza minima del QT è settata a 16x16, la grandezza massima
del BT è settata 128x128, la grandezza massima del TT è settata a 64x64, la grandezza minima del
BT è uguale a quella del TT e sono entrambe 4x4 ed infine la profondità massima dell’MTT (Multi
Type Tree) è 4. Il partizionamento ad albero quaternario viene dunque inizialmente applicato al
CTU per ottenere i nodi foglia e, questi, posso essere da 16x16 (cioè la grandezza minima del QT)
fino ad un massimo di 128x128 (cioè la grandezza del CTU). Se il nodo foglia QT è 128x128, allora
questo non verrà più diviso dall’albero binario visto che la dimensione supera la grandezza massima
del BT e del TT che sono 64x64, altrimenti questo sarebbe stato partizionato ulteriormente
dall’MTT (Multi Type Tree). Dunque, il nodo foglia dell’albero quaternario è anche il nodo radice
dell’MTT (Multi Type Tree) ed ha profondità 0. Quando la profondità raggiunge il massimo (cioè
4), non vengono più fatte divisioni; allo stesso modo, quando il nodo MTT (Multi Type Tree) è
largo tanto quanto la minima grandezza del BT ed uguale alla minima grandezza del TT * 2 (o più
piccolo), non vengono più fatte divisioni orizzontali e la stessa cosa vale per l’altezza e le divisioni
verticali. Per consentire blocchi di luma da 64x64 e di chroma da 32x32 nei decoder hardware, la
divisione TT non è consentita qualora la larghezza o l’altezza del luma sia maggiore di 64 e
maggiore di 32 per il chroma.

Divisione TT non consentita per blocchi da 128x128

Nell’H.266 lo schema di codifica ad albero supporta la possibilità di avere una struttura separata per
il luma e per il chroma: per gli slice P e B, i CTB di luma e chroma devono condividere la stessa
struttura, ma gli I possono avere strutture diverse per luma e chroma. Quando viene applicata una
modalità di codifica ad albero con blocchi diversi, il CTB del luma è partizionato in CU da una
struttura ed il chroma è partizionato in CU da un’altra struttura, il che significa che un CU in uno
slice I potrebbe avere un blocco di luma o blocchi di due componenti di chroma ed un CU in uno
slice P o B ha invece tutte e 3 le componenti (a meno che il video non sia in bianco e nero).

- Partizionamento dei CU sui bordi dell’immagine

Come già visto nell’H.265, quando una porzione di un blocco del nodo di un albero eccede il bordo
inferiore o destro dell’immagine, avviene un partizionamento finché tutti i sample di ogni CU
codificato sono situati all’interno dei bordi dell’immagine.
Nell’H.266 abbiamo che se una portzione di un blocco del nodo di un albero eccede la parte
inferiore o destra del bordo dell’immagine e non è consentito un partizionamento QT, BT o TT a
causa delle restrizioni sulla grandezza del blocco, allora il blocco deve per forza essere partizionato
con la modalità di partizionamento QT.
Infatti, se il blocco è un nodo QT e la grandezza del blocco è più grande della grandezza minima del
QT, allora il blocco è costretto ad essere diviso con la modalità di partizionamento QT, altrimenti il
blocco viene diviso con la modalità BT_HOR. Se il blocco è un nodo QT e la grandezza del blocco
è più grande della grandezza minima QT ma più grande della grandezza massima del BT, abbiamo
di nuovo la modalità di partizionamento QT, mentre se è più piccolo della grandezza massima BT,
allora avremo la modalità di partiazionamento BT_HOR; stessa cosa se il blocco è un nodo BTT o
se la grandezza del blocco è più piccola (o pari) alla grandezza minima QT. La modalità di
partizionamento BT_VER, invece, si verifica se abbiamo un nodo QT con grandezza del blocco più
grande della grandezza minima QT e più piccola (o pari) alla grandezza massima BT; stessa cosa se
il blocco è un nodo BTT o se la grandezza del blocco è più piccola (o pari) alla grandezza minima
QT.

- Restrizioni sui partizionamenti (divisioni) CU ridondanti

Il Quadtree con struttura di codifica a blocchi NMTT (Nested Multi Type Tree) fornisce una
struttura di partizionamento a blocchi altamente flessibile. Grazie ai tipi di partizionamento
supportati nell’MTT (Multi Type Tree), diversi pattern di partizionamento potrebbero risultare nella
stessa struttura di codifica a blocchi. Nell’H.266, alcuni di questi pattern di partizionamento
(divisione) ridondanti non sono consentiti.

Casi di pattern di partizionamento ridondanti di alberi binari e ternari

Due livelli di un partizionamento binario consecutivi in una direzione potrebbero avere la stessa
struttura di codifica a blocchi di un partizionamento di un albero ternario seguito da un
partizionamento ad albero binario della partizione centrale. In questo caso, il partizionamento ad
albero binario (nella direzione data) per la partizione centrale del partizionamento di un albero
ternario è proibito e, questa restrizione, vale per tutti i CU in tutte le immagini. Quando i
partizionamenti sono proibiti, la segnalazione degli elementi di sintassi corrispondenti viene
modificata per tener conto dei casi proibili. Ad esempio, quando viene identificato qualsiasi caso
nella figura qui sopra, sapremo che il partizionamento binario è proibito per un CU di una
partizione centrale perché non verrà segnalato il flag di divisione CU Binaria e sarà assunto come
uguale a 0 dal decoder.

- VPDU – Virtual Pipeline Data Unit

I VDPU (Virtual Pipeline Data Unit) sono definiti come unità non sovrapposte in una immagine.
Nei decoder hardware, i VPDU successivi sono processati a più intervalli della pipeline in
contemporanea. La grandezza del VPDU è più o meno proporionale alla grandezza del buffer nella
maggior parte della pipeline, quindi è importante tenere piccola la grandezza del VPDU. Nella
maggior parte dei decoder hardware, la grandezza del VPDU può essere settata al pari della
massima grandezza di trasformata TB (Transform Block). In ogni caso, nell’H.266, le partizioni TT
(Ternary Tree) e BT (Binary Tree) possono portare ad un aumento della grandezza del VPDU. Per
poter tenere la grandezza del VPDU a 64x64 sample di luma, vengono applicate delle restrizioni, ad
esempio il partizionamento TT non è consentito per un CU con larghezza od altezza (o entrambe)
pari a 128. Per un CU 128xN con N <= 64 (cioè con larghezza uguale a 128 ed altezza più piccola
di 128) non è consentito il BT orizzontale; allo stesso modo, se abbiamo un CU Nx128 con N <= 64
allora il BT verticale non è consentito.

Esempio di partizionamento TT e BT non consentito

- Partizionamento del Chroma Intra e restrizioni sulla predizione

Negli encoder e decoder hardware, il throughput scende quando un’immagine ha tanti piccoli
blocchi intra a causa della dipendenza tra i blocchi intra adiacenti. La generazione del predittore di
un blocco intra richiede che i sample dei bordi superiore e sinistro siano ricostruiti dai blocchi
adiacenti, dunque la predizione intra deve essere processata in maniera sequenziale blocco per
blocco. Nell’H.265, i sample di luma intra di un CU più piccoli che si possono avere sono da 8x8 e
può essere diviso ulteriormente in 4 unità di predizione intra da 4x4, mentre le componenti del
chroma non possono essere divise ulterioremnte. Dunque, il peggior caso possibile per un hardware
è quando vengono processati blocchi intra di chroma da 4x4 e blocchi intra di luma da 4x4.
Nell’H.266, per semplificare la vita agli hardware, i CB intra del chroma più piccoli di 16 sample di
chroma (quindi di grandezza 2x2, 4x2 e 2x4) e quelli che hanno una larghezza più piccola di 4
sample (quindi di grandezza 2xN) non sono consentiti e viene appositamente limitato il
partizionamento. In un albero di codifica singolo, l’unità di predizione intra del chroma più piccola
è definità come un nodo di codifica ad albero la cui grandezza del blocco del chroma è maggiore (o
uguale) a 16 sample ed ha almeno un blocco figlio di luma più piccolo di 64 sample e viene detta
SCIPU (Smallest Chroma Intra Prediction Unit). Alternativamente, anche un nodo di codifica ad
albero in cui il blocco di chroma non è 2xN ed ha almeno un blocco di luma figlio da 4xN sample di
luma. In ogni SCIPU (Smallest Chroma Intra Prediction Unit) tutti i CB devono essere inter,
altrimenti, se uno di questi non è inter, allora anche tutti gli altri non devono essere inter (quindi
intra). Nel caso di una SCIPU (Smallest Chroma Intra Prediction Unit) non inter, il chroma non
deve essere partizionato ulteriormente e solo il luma può esserlo. In questo modo, i piccoli CB intra
di chroma con grandezza inferiore a 16 sample o con grandezza 2xN vengono rimossi. Non solo,
quando si hanno SCIPU non inter, neanche lo scaling del chroma viene applicato. In questo caso,
non viene segnalata alcuna sintassi aggiuntiva ed il fatto che una SCIPU sia non inter può essere
derivato dalla modalità di predizione del primo CB di luma nella SCIPU stessa. Il tipo di SCIPU è
assunto come non inter se lo slice corrente è uno slice I o se la SCIPU corrente ha una partizione di
luma da 4x4 dopo che c’è già stata una divisione (questo perché non esistono blocchi da 4x4 inter
nell’H.266, quindi dev’essere sicuramente intra), altrimenti il tipo di SCIPU viene indicato da un
flag prima di fare il parsing dei CU nella SCIPU stessa. Per gli alberi doppi in un’immagine intra, i
blocchi di chroma intra da 2xN vengono rimossi disabilitando i partizionamenti verticali binari e
ternari per le partizioni di chroma da 4xN ed 8xN. I blocchi di chroma da 2x2, 4x2 e 2x4 vengono
anch’essi rimossi dalle restizioni di partizionamento. Inoltre, viene utilizzata una restrizione sulla
grandezza dell’immagine per evitare blocchi di chroma intra da 2x2, 2x4, 4x2 e 2xN agli angoli
dell’immagine.

- Modalità di codifica Intra con 67 modelli di predizione Intra

Per catturare le direzioni arbitrarie dei contorni che i video hanno nella vita reale, il numero delle
modalità di direzione intra in H.266 è stato aumentato da 33 (dell’H.265) a 67. Le nuove modalità
di direzione non presenti nell’H.265 sono rappresentate di seguito da delle frecce rosse e le modalità
DC planar rimangono le stesse:

67 Modalità di Predizione Intra

Queste modalità di predizione intra più “dense” valgono per tutti i blocchi, a prescindere dalla
grandezza, sia per le predizioni intra di luma che di chroma. Nell’H.266, molte modalità di
predizione intra angolari tipiche degli anni passati sono state sostituite con modalità di predizione
intra ad ampio angolo adattive per i blocchi non quadrati (e, di queste, ne parlerò più avanti). In
H.265, ogni blocco intra deve essere quadrato e la lunghezza di ognuno dei suoi lati deve essere una
potenza di 2, dunque non sono necessarie divisioni per generare un predittore intra usando la
modalità DC. Nell’H.266, i blocchi possono avere una forma rettangolare che necessità dell’uso di
un operatore di divisione per blocco nel caso generale. Per evitare le operazioni di divisione per la
predizione DC, solamente il lato più lungo viene utilizzato per computare la media per i blocchi non
quadrati.
- Modalità di Codifica Intra

Per mantenere la complessità della generazione della lista MPM (Most Probable Mode) bassa, viene
utilizzato un modo di codifica intra con 6 MPM considerando due modalità intra vicine disponibili.
Per costruire la lista MPM vengono considerati i seguenti aspetti:

1) Modalità Intra di Default


2) Modalità Intra Vicine
3) Modalità Intra Derivate

Una lista unificata da 6 MPM viene utilizzata per i blocchi intra, a prescindere dall’utilizzo o meno
degli strumenti di codifica MRL ed ISP. La lista MPM è costruita sulla base delle modalità intra dei
blocchi vicini sinistro e superiore.
Ad esempio, quando non è disponibile un blocco confinante, la sua modalità intra viene settata su
“Planar” di default. Se entrambe le modalità sinistra e superiore sono modalità non agolari, allora:

Lista MPM -> {Planar, DC, V, H, V – 4, V + 4}

Se una delle modalità sinistra o superiore è in modalità angolare e l’altra è non agolare, allora setta
una modalità massima come modalità più grande:

Lista MPM -> {Planar, Massima, DC, Massima – 1, Massima + 1, Massima – 2}

Se la sinistra e superiore sono entrambe angolari e sono diverse tra loro, allora setta una modalità
massima come modalità più grande e, se la differenza tra la modalità sinistra e superiore è compresa
tra 2 e 62, allora:

Lista MPM -> {Planar, Sinistra, Superiore, DC, Massima – 1, Massima + 1}

altrimenti:

Lista MPM -> {Planar, Sinistra, Superiore, DC, Massima – 2, Massima + 2}

Se la sinistra e superiore sono entrambe angolari ma non sono diverse tra loro, cioè se sono uguali,
allora:

Lista MPM -> {Planar, Sinistra, Sinistra – 1, Sinistra + 1, DC, Sinistra – 2}

Inoltre, il primo bin dell’index MPM è codificato come CABAC. In totale, vengono usati 3 contesti
a seconda che il blocco intra corrente sia MRL, ISP o un normalissimo blocco intra. Durante il
processo di generazione della lista da 6 MPM, viene effettuato un processo di “potatura” per
rimuovere le modalità doppie in modo che solamente le modalità singole (uniche) siano incluse
nella lista MPM. Per la codifica entropica delle 61 modalità non MPM, viene utilizzato un TBC
(Truncated Binary Code).

- Predizioni intra ad ampio angolo per i blocchi non quadrati

Le direzioni di predizione intra angolari convenzionali sono definite da 45° a -135° in senso orario.
Nell’H.266, molte modalità di predizione intra angolari convenzionali sono state sostituite
adattivamente da delle modalità di predizione intra ad ampio angolo per blocchi non quadrati. Le
modalità sostituite sono segnalate usando le modalità di index originali che sono state rimappate
sugli index delle modalità ad ampio angolo dopo il parsing. Il numero totale di modalità di
predizione intra rimane 67 così come rimane invariato il metodo di codifica della modalità intra.

Sample di riferimento per la predizione intra ad ampio angolo


Per supportare queste direzioni di predizione, il riferimento superiore con lunghezza 2W + 1 e
quello sinistro con lunghezza 2H+1 sono definiti come sopra, mentre il numero delle modalità che
sono state sostituite nella modalità di direzione ad ampio angolo dipende dall’aspect ratio del blocco
e sono:

Aspect ratio Modalità di predizione intra sostituite


Larghezza / Altezza = 16 Modalità 12, 13,14,15
Larghezza / Altezza = 8 Modalità 12, 13
Larghezza / Altezza = 4 Modalità 2,3,4,5,6,7,8,9,10,11
Larghezza / Altezza = 2 Modalità 2,3,4,5,6,7,
Larghezza / Altezza = 1 Nessuna
Larghezza / Altezza = 1/2 Modalità 61,62,63,64,65,66
Larghezza / Altezza = 1/4 Modalità 57,58,59,60,61,62,63,64,65,66
Larghezza / Altezza = 1/8 Modalità 55, 56
Larghezza / Altezza = 1/16 Modalità 53, 54, 55, 56
Modalità di predizione intra sostituite dalle modalità ad ampio angolo

Problema della discontinuità in caso di direzioni oltre i 45°

Come mostrato sopra, due sample predetti verticalmente adiacenti potrebbero usare due sample di
riferimento non adiacenti nel caso della predizione intra ad ampio angolo. Dunque, vengono
applicati filtri di sample di riferimento passa-basso e smoothing alla predizione ad ampio angolo per
ridurre l’effetto negativo del maggiore gap ∆pα se una modalità ad ampio angolo rappresenta un
offset non frazionario. Ci sono 8 modalità nella modalità ad ampio angolo che soddisfano questa
condizione, ovvero:

[-14, -12, -10, -6, 72, 76, 78, 80]

Quando viene predetto un blocco da queste modalità, i sample nel buffer di riferimento sono copiati
direttamente senza applicare alcuna interpolazione.
Con questa modifica, il numero dei sample che devono essere sottoposti a smoothing viene ridotto.
Inoltre, questo allinea il design delle modalità non frazionarie nelle modalità di predizione
convenzionali ed ad ampio angolo. Nell’H.266 sono supportati i formati di chroma 4:2:0, 4:2:2 e
4:4:4. La tabella di derivazione della Chroma DM (Chroma Derived Mode) per il 4:2:2 era stata
inizialmente presa dall’H.265 estendendo il numero di entries da 35 a 67 per allinearla con
l’estensione delle modalità di predizione intra, però, siccome quella dell’H.265 non supportava gli
angoli di predizione sotto a -135° e sopra ai 45°, le modalità di predizione del luma intra che
andavano da 2 a 5 sono state mappate a 2, dunque la tabella di derivazione del Chroma DM
(Chroma Derived Mode) è stata aggiornata rimpiazzando alcuni valori delle entries della tabella di
mapping per convertire gli angoli di predizione in maniera più precisa per i blocchi di chroma.

- MDIS – Mode Dependent Intra Smoothing

Per migliorare l’accuratezza della predizione intra direzionale vengono utilizzati filtri di
interpolazione intra a 4 tap. Nell’H.265 è stato utilizzato un filtro di interpolazione lineare a 2 tap
per generare il blocco di predizione intra nelle modalità di predizione direzionale (esclusi i
predittori Planar e DC). Nell’H.266, viene utilizzato un filtro di interpolazione Gaussiana a 4 tap
semplificato da 6bit ma solo per le modalità intra direzionali, mentre le modalità di predizione intra
non direzionali restano invariate. La selezione dei filtri a 4 tap è effettuata secondo la condizione
MDIS (Mode Dependent Intra Smoothing) per le modalità di predizione direzionale intra che
forniscono i displacement non frazionari, cioè tutte le modalità direzionali escluse la 2, la
HOR_IDX, la DIA_IDX, la VER_IDX e la 66. La modalità di predizione intra direzionale è
classificata in uno dei seguenti gruppi: modalità verticali od orizzontali (HOR_IDX, VER_IDX),
modalità diagonali che rappresentano gli angoli multipli di 45° (2, DIA_IDX, VDIA_IDX), altre
modalità direzionali. Se la modalità di predizione intra direzionale è classificata come appartenente
al gruppo A, allora non vengono applicati filtri ai sample di riferimento per generare i sample
predetti, altrimenti, se appartiene al gruppo B, allora un filtro di sample di riferimento 1, 2, 1 può
essere applicato (a seconda della condizione MDIS – Mode Dependent Intra Smoothing) ai sample
di riferimento per copiare ulteriormente questi valori filtrati in un predittore intra secondo la
direzione selezionata, ma non vengono applicati filtri di interpolazione. C’è un altro caso ancora,
però, ovvero il caso in cui la modalità di predizione appartiene al gruppo C; in questo caso, viene
applicato ai sample di riferimento un semplice filtro di interpolazione dei sample di riferimento
intra per generare un sample predetto che cada in una posizione frazionaria o intera tra i sample di
riferimento secondo la direzione scelta (in questo caso quindi non c’è alcun filtraggio dei sample di
riferimento).

- Modello di Predizione Lineare Cross-Component

Per ridurre la ridondanza cross-component, nell’H.266 viene utilizzato un modello di predizione


lineare Cross-Component - detto CCLM (Cross-Component Linear Model) – in cui i sample di
chroma sono predetti sulla base dei sample di luma ricostruiti dello stesso CU usando un modello
lineare:

in cui pred c (i,j) pred c (i,j) rappresentano i sample di chroma predetti in un CU e rec L (i, j) e
rec L ‘ (i, j) rappresentano i sample di luma sotto-campionati e ricostruiti dello stesso CU. I
parametri CCLM (Cross-Component Linear Model Prediction) αα e ββ sono derivati al massimo
con 4 sample di chroma vicini (confinanti) ed i loro corrispettivi sample di luma sotto-campionati.
Supponiamo che le dimensioni di un blocco di chroma siano WxH (Width x Height, cioè Larghezza
x Altezza), allora W’ e H’ sono:
- W’ = W, H’ = H quando viene applicata la modalità LM -
- W’ = W + H quando viene applicata la modalità LM-A -
- H’ = H + W quando viene applicata la modalità LM-L -

Le posizioni vicine (confinanti) di sopra sono denotate come S[0, -1]...S[W’- 1, -1] e le posizioni
vicine (confinanti) sinistre sono denotate come S[- 1, 0]...S[- 1, H’ – 1]. Poi, i 4 sample sono
selezionati come:

- S[W’ / 4, - 1], S[3*W’/4, - 1], S[- 1, H’ / 4], S[- 1, 3*H’/4] quando è applicata la modalità LM ed
entrambi i sample vicini (confinanti) superiore e sinistro sono disponibili.

- S[W’ / 8, - 1], S[3*W’/8, - 1], S[5*W’/8, -1], S[7*W’/8, - 1] quando è applicata la modalità LM-A
oppure solamente i sample vicini (confinanti) superiori sono disponibili.

- S[- 1, H’/8], S[- 1, 3*H’/8], S[- 1, 5*H’/8], S[-1, 7*H’/8] quando è applicata la modalità LM-L
oppure solamente i sample sinistri sono disponibili.

I 4 sample di luma vicini (confinanti) alle posizioni selezionate vengono sotto-campionati e


comparati 4 volte per trovare 2 valori più piccoli: x0A e x1A e due valori più grandi x0B e x1B. I valori
dei loro corrispondenti sample di chroma sono denotati come y0A, y1A, y0B e y1B. Poi, xA, xB, yA e yB
sono derivati come:

Xa=(x0A + x1A +1)>>1; Xb=(x0B + x1B +1)>>1; Ya=(y0A + y1A +1)>>1; Yb=(y0B + y1B +1)>>1

Infine, i parametri del modello lineare α e β sono ottenuti secondo le seguenti equazioni:

Ad esempio, se volessimo rappresentare la posizione dei sample sinistro e superiore e quella dei
sample del blocco che viene sottoposto al processing con la CCLM (Cross Component Linear
Model Prediction), avremmo:

Posizione dei sample usati per la derivazione di α e β


L’operazione di divisione per calcolare il parametro α α è implementata con un look-up table. Per
ridurre la memoria richiesta per salvare la stessa, il valore diff (differenza tra i valori massimo e
minimo) ed il parametro α α è espresso con una notazione esponenziale. Ad esempio, diff è
approssimato con una parte significativa a 4bit ed un esponente, dopodiché, la tabella per 1/diff è
ridotta in 16 elementi per 16 valori del significante:

DivTable [] = { 0, 7, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 0 }

Questo porta quindi un beneficio sia nella riduzione della complessità dei calcoli che allo spazio in
memoria richiesto per salvare le tabelle richieste. Inoltre, i template superiore e sinistro possono
essere utilizzati insieme per calcolare i coefficienti del modello lineare ed alternativemente nelle
altre 2 modalità LM chiamate LM_A ed LM_L. Nella modalità LM_A, solamente i template
superiori sono usati per calcolare i coefficienti del modello lineare. Per avere più sample, i template
superiori sono estesi a W+H. Nella modalità LM_L, solamente i template sinistri sono utilizzati per
calcolare i coefficienti del modello lineare. Per avere più sample, i template sinistri sono estesi ad
H+W. Per un blocco non quadrato, i template superiori sono estesi a W+W, mentre quelli sinistri
sono estesi a H+H. Per matchare le locazioni dei sample di chroma per sequenze video in 4:2:0,
vengono applicati due tipi di filtri di sotto-campionamento ai sample di luma per raggiungere un
rapporto di sotto-campionamento 2:1 sia nella direzione orizzontale che in quella verticale. La
selezione del filtro di sotto-campionamento è specificata da un flag di livello SPS. I due filtri di
sotto-campionamento, che corrispondono ai contenuti di Tipo 0 e Tipo 2, sono:

Quando la linea di riferimento superiore è al confine del CTU, solamente una linea del luma (la
linea generale del buffer nella predizione intra) viene utilizzata per fare i sample di luma sotto-
campionati. Questa computazione di parametri fa parte del processo di decoding e non è solo
un’operazione di ricerca che effettua l’encoder, per questo non c’è bisogno di utilizzare alcuna
sintassi per trasmettere i valori di α e β al decoder. Per la modalità di codifica del chroma intra,
sono consentiti un totale di 8 modalità intra. Queste modalità includono 5 modalità intra tradizionali
e 3 modalità dette CCLM (Cross Component Linear Model), LM_A ed LM_L. Il processo di
segnalazione e derivazione della modalità del chroma sono:

Modalità di predizione intra del luma corrispondenti


Modalità di Predizione del Chroma
0 50 18 1 X (0<=X<=66)

0 66 0 0 0 0

1 50 66 50 50 50

2 18 18 66 18 18

3 1 1 1 66 1

4 0 50 18 1 X

5 81 81 81 81 81
6 82 82 82 82 82

7 83 83 83 83 83
Derivazione della modalità di predizione del chroma dalla modalità del luma
quando CCLM_IS è abilitato

La modalità di codifica del chroma dipende direttamente dalla modalità di predizione intra del
corrispondente blocco di luma. Visto che la struttura di partizionamento a blocchi separati per le
componenti di luma e chroma è abilitata negli slice I, un blocco di chroma potrebbe corrispondere a
più blocchi di luma, quindi, per la modalità di chroma DM, la modalità di predizione intra del
corrispondente blocco di luma che copre la posizione centrale dell’attuale blocco di chroma è
ereditata direttamente e viene utilizzata una singola tabella di binarizzazione a prescindere se il flag
SPS_CCLM_ENABLED è presente o meno:

Valore della modalità di predizione intra del chroma Bin string


4 00
0 0100
1 0101
2 0110
3 0111
5 10
6 110
7 111
Tabella di binarizzazione unificata per la modalità di predizione del chroma

I primi bin indicano se è una modalità regolare (0) o LM (1). Se è una modalità LM, allora il bin
successivo indica se è LM_CHROMA (0) o meno. Se non è LM_CHROMA, allora il prossimo bin
indica se è LM_L (0) o LM_A (1). In questo caso, quando il flag SPS_CCLM_ENABLED è settato
a 0, il primo bin della tabella di binarizzazione della corrispondente modalità di predizione intra del
chroma può essere “dimenticato” prima della codifica entropica (cioè viene assunto come 0 e quindi
può non essere codificato). Questa tabella di binarizzazione viene utilizzata sia se il flag
SPS_CCLM_ENABLED è settato su 0 sia se è settato su 1. I primi 2 bin sono Context Coded con il
loro Context Model, mentre il resto sono Bypass Coded. Inoltre, per ridurre la latenza luma-chroma
in un albero duale, quando il nodo di codifica ad albero da 64x64 sample di luma è partizionato con
un “Not Split” (cioè non dividere) e l’ISP non è usato per i CU 64x64, oppure QT, i CU del chroma
nel nodo di codifica ad albero del chroma 32x32 / 32x16 possono usare il CCLM (Cross
Component Linear Model). In particolare, se il nodo del chroma da 32x32 è Not Split (non dividere)
o partizionato QT, tutti i CU del chroma nel nodo posso usare il CCLM (Cross Component Linear
Model), mentre se il nodo da 32x32 di chroma è partizionato con BT Horizontal ed il nodo figlio da
32x16 non è diviso o usa lo split BT Vertical, allora tutti i CU del chroma nel nodo di chroma 32x16
possono usare il CCLM (Cross Component Linear Model). In tutte le altre condizioni di divisione
(split) della codifica ad albero del luma e chroma, il CCLM (Cross Component Linear Model) non è
consentito per i CU del chroma.
- Combinazione della predizione intra dipendente dalla posizione

Nell’H.266, i risultati della predizione intra DC, planar e varie altre modalità angolari è modificato
ulteriormente dalla combinazione della predizione intra dipendente dalla posizione detta metodo
PDPC (Position Dependent Intra Prediction Combination). Il PDPC (Position Dependent Intra
Prediction Combination) è un metodo di predizione intra che invoca una combinazione dei sample
di riferimento vicini (confinanti) non filtrati e la predizione tipica dell’H.265 con i sample di
riferimento vicini (confinanti) filtrati. Il PDPC (Position Dependent Intra Prediction Combination) è
applicato alle seguenti modalità intra senza doverlo segnalare: planar, DC, orizzontale, verticale,
modalità algolare inferiore sinistra e le sue 8 modalità angolari adiacenti ed anche alla modalità
angolare superiore destra ed alle sue 8 modalità angolari adiacenti. Il sample di predizione pred(x’,
y’) è predetto usando una modalità di predizione intra (DC, planar, angolare) ed una combinazione
lineare dei sample di riferimento secondo la seguente equazione:

pred(x’,y’)=(wL×R−1,y’+ wT×Rx’,−1−wTL ×R−1,−1+(64 − wL − wT+wTL)×pred(x’,y’) +32)>>6

in cui Rx,−1, R−1,y rappresenta i sample di riferimento situati ai confini superiore e sinistro del sample
attuale (x, y) rispettivamente e R−1,−1 rappresenta il sample di riferimento situato all’angolo superiore
sinistro del blocco corrente. Se il PDPC (Position Dependent Intra Prediction Combination) è
applicato alle modalità intra DC, planar, orizzontale e verticale, non sono necessari altri filtri, come
richiesto invece nel caso del filtro di confine di modalità DC H.265 o nel caso dei filtri di confine di
modalità orizzontale/verticale. Il processo PDPC (Position Dependent Intra Prediction
Combination) per le modalità DC e planar è identico e vengono evitate operazioni di clipping. Per
le modalità angolari, il PDPC Scale Factor viene aggiustato in modo che il controllo del range non
sia necessario e la condizione sull’angolo per consentire il PDPC (Position Dependent Intra
Prediction Combination) è rimossa (viene usato scale >= 0). Inoltre, il peso del PDPC è basato su
32 in tutti i casi di modalità angolare. I pesi del PDPC sono dipendenti dalle modalità di predizione
seguenti:

Modalità di Predizione wT wL wTL


Diagonale Superiore Destra 16 >> ( ( y’<<1 ) >> 16 >> ( ( x’<<1 ) >> 0
shift) shift)
Diagonale Inferiore Sinistra 16 >> ( ( y’<<1 ) >> 16 >> ( ( x’<<1 ) >> 0
shift ) shift )
Diagonale Adiacente 32 >> ( ( y’<<1 ) >> 0 0
Superiore Destra shift )
Diagonale Adiacente 0 32 >> ( ( x’<<1 ) >> 0
Inferiore Sinistra shift )
Esempio di pesi PDPC secondo i modalli di predizione
Il PDPC è applicato al blocco con sia larghezza (width) che altezza (height) maggiori o uguali a 4.
La definizione dei sample di riferimento (Rx,−1, R−1,y e R−1,−1) per il PDPC applicati su vari modalli di
predizione è illustrata di seguito.
Definizione dei sample usati dal PDPC applicati alle modalità angolari Diagonale ed Adiacente

I sample di predizione pred(x’,y’) sono situati in (x’, y’) all’interno del blocco di predizione. Ad
esempio, la coordinata x del sample di riferimento Rx,−1 è data da x = x’ + y’ + 1 e la coordinata y del
sample di riferimento R−1,y è data in maniera simile da y = x’ + y’ + 1 per le modalità diagonali. Per
le altre modalità angolari, i sample di riferimento Rx,−1 e R−1,y possono essere situati in una posizione
sample frazionaria. In tal caso, vengono usati i valori dell’intero più vicino.

- Predizione Intra MRL (Multiple Reference Line)

La predizione intra MRL (Multiple Reference Line) semplicemente utilizza più reference line (linee
di riferimento) per la predizione intra.
Esempio di 4 Reference Line vicine ad un blocco di predizione

Nello schema di sopra abbiamo 4 Reference Line in cui i sample dei segmenti A ed F non sono
“ricavati” dai sample vicini ricostruiti ma bensì vengono paddati dai sample più vicini dei segmenti
B ed E rispettivamente. La predizione intra immagine dell’H.265 utilizza la Reference Line più
vicina (cioè la 0), mentre nella predizione intra MRL (Multiple Reference Line) dell’H.266 sono
state incluse altre Reference Line, ovvero la Reference Line 1 e 3. L’index della Reference Line
slezionata (MRL_IDX) è segnalato ed utilizzato per generare il predittore intra. Per i Reference
Line IDX, che sono più grandi di 0, sono incluse solamente le modalità di Reference Line
aggiuntive nella lista MPM e viene segnalato solamente l’MPM senza le modalità rimanenti.
L’index di Reference Line è segnalato prima delle modalità di predizione intra e la modalità planar
è esclusa dalle modalità di predizione intra nel caso venga segnalato un Reference Line Index che
non sia zero. L’MRL (Multiple Reference Line) è disabilitato per la prima linea di blocchi
all’interno di un CTU per prevenire l’uso di sample di riferimento estesi al di fuori della linea CTU
corrente. Inoltre, il PDPC viene disabilitato quando viene utilizzata una linea aggiuntiva. Per la
modalità MRL, la derivazione del valore DC nella modalità di predizione DC intra per le Reference
Line che non sono zero è allineata con quella del Reference Line Index 0. L’MRL richiede il
salvataggio di 3 Reference Line di luma vicine (confinanti) con un CTU per generare le predizioni,
così come li richiede anche il CCLM (Cross Component Linear Model) per i suoi filtri di sotto-
campionamento. Per utilizzare le stesse 3 linee, la definizione dell’MLR è allineata al CCLM (Cross
Component Linear Model) riducendo così i requisiti di storage per i decoder.
- Sotto-Partizioni Intra

Le sotto-partizioni intra sono dette ISP (Intra Sub-Partitions) e dividono i blocchi predetti intra di
luma - verticalmente od orizzontalmente - in 2 o 4 sotto-partizioni a seconda della grandezza del
blocco. Ad esempio, la grandezza di blocco minima per le ISP (Intra Sub-Partitions) è 4x8 (od 8x4).
Se la grandezza del blocco è più grande di 4x8 (od 8x4) allora il blocco corrispondente è diviso da 4
sotto-partizioni. C’è da dire che blocchi ISP (Intra Sub-Partitions) Mx128 (con M <= 64) e 128xN
con N <= 64 possono generare problemi con VDPU da 64x64. Ad esempio, un CU da Mx128 nel
caso a singolo albero ha un TB di luma da Mx128 e 2 TB di chroma corrispondenti da [(M/2)x64]
Se il CU usa l’ISP, allora il TB di luma verrà diviso in 4 TB Mx32 (solo con divisione orizzontale se
possibile), ognuno dei quali è più piccolo di un blocco da 64x64, tuttavia, nel design attuale i
blocchi di chroma ISP non sono divisi, dunque, entrambe le componenti di chroma avranno una
grandezza maggiore di un blocco da 32x32. Analogamente, una situazione simile si può creare con
un CU da 128xN usando l’ISP; dunque, questi due casi sono un problema per la pipeline di un
decoder 64x64. Per questo motivo, i CU che possono usare l’ISP sono stati ristretti ad un massimo
di 64x64 come grandezza.

Esempio di sotto-partizioni a seconda della grandezza del blocco (4x8 CU, 8x4 CU etc)
Tutte le sotto-partizioni devono adempiere la condizione di avere almeno 16 sample. Nelle ISP
(Intra Sub Partitions), la dipendenza della predizione dei sotto-blocchi da 1xN/2xN sui valori
ricostruiti dei sotto-blocchi da 1xN/2xN decodificati precedentemente dei blocchi di codifica non è
consentita in modo che la larghezza minima della predizione per i sotto-blocchi sia di 4 sample. Ad
esempio, un blocco di codifica da 8xN (N>4) è codificato usando l’ISP con divisione
(partizionamento) verticale viene diviso (partizionato) in 2 regioni di predizione ognuna di
grandezza 4xN e 4 trasformate di grandezza 2xN. Inoltre, un blocco di codifica da 4xN che è
codificato usando l’ISP con divisione (partizionamento) verticale è predetto usando l’intero blocco
da 4xN e vengono utilizzate 4 trasformate ognuna da 1xN. Le dimensioni di trasformata da 1xN e
2xN sono consentite, ma comunque viene presupposto che le trasformate di questi blocchi nella
regione da 4xN siano effettuate in parallelo. Ad esempio, quando una regione di predizione da 4xN
contiene 4 trasformate da 1xN, non c’è una trasformata nella direzione orizzontale; la trasformata
nella direzione verticale può essere fatta da una singola trasformata da 4xN nella direzione
verticale. In maniera similare, quando una regione di predizione da 4xN contiene 2 blocchi di
trasformata da 2xN, l’operazione di trasformata dei 2 blocchi da 2xN in ogni direzione (orizzontale
e verticale) può essere fatta in parallelo. Dunque, non si ha alcun rallentamento nel processare
questi blocchi più piccoli rispetto a processare direttamente un blocco da 4x4 codificato
normalmente in intra.

Grandezza del Blocco Grandezza del Coeff. Del Gruppo


1 × N , N ≥ 16 1 ×16
N ×1 , N ≥ 16 16 ×1
2×N ,N ≥8 2 ×8
N ×2 , N ≥ 8 8 ×2
Tutti gli altri casi possibili 4 ×4
M×N
Grandezza del Coeff. Del Gruppo - Codifica Entropica

Per ogni sotto-partizione, i sample ricostruiti sono ottenuti aggiungendo il segnale residuo al
segnale di predizione. Dunque, un segnale residuo viene generato da un processo tipo la decodifica
entropica, la quantizzazione inversa e la trasformata inversa. A questo punto, i valori deo sample
ricostruiti di ogni sotto-partizione sono disponibile per generare la predizione della sotto-partizione
successiva ed ogni sotto-partizione è processata ripetutamente. Inoltre, la prima sotto-partizione ad
essere processata è quella che contiene il sample superiore sinistro del CU e poi si prosegue in
basso (partizionamento orizzontale) o verso destra (partizionamento verticale). Come risultato, i
sample di riferimento usati per generare i segnali di predizione delle sotto-partizioni vengono situati
alla sinistra ed in alto delle linee. Tutte le sotto-partizioni condividono la stessa modalità intra. Se
un blocco ha un Index MRL (Multiple Reference Line) diverso da 0, allora la modalità di codifica
ISP verrà assunta come 0 e quindi l’informazione sulla modalità ISP non verrà inviata al decoder.
Le dimensioni dei sotto-blocchi di codifica entropica sono stati modificati in modo da avere 16
sample in tutti i casi possibili come mostrato nella tabella qua sopra. Tutte le nuove dimensioni
influenzano solamente i blocchi prodotti dall’ISP in cui una delle dimensioni è inferiore a 4 sample;
in tutti gli altri casi, i coeff. mantengono le dimensioni da 4x4. Per quanto riguarda la codifica CBF,
viene assunto che si abbia almeno una sotto-partizione con un CBF non zero, dunque, se n è il
numero delle sotto-partizioni e le prime n-1 sotto-partizioni hanno prodotto un CBF zero, allora il
CBF della n-esima sotto-partizione sarà assunto essere 1. Per quanto riguarda l’utilizzo MPM, il
flag MPM sarà assunto essere in un blocco codificato dalla modalità ISP e la lista MPM è
modificata per escludere la modalità DC e dare priorità alle modalità intra orizzontali per il
partizionamento orizzontale ISP (lo stesso vale per le modalità intra verticali per il partizionamento
verticale). Per quanto riguarda le restrizioni sulla grandezza di trasformata, tutte le trasformate ISP
con una lunghezza maggiore di 16 punti utilizzano la DCT II. Per quanto riguarda i PDPC, quando
un CU utilizza la modalità di codifica ISP, i filtri PDPC non saranno applicati alle sotto-partizioni
risultanti. Per quanto riguarda il flag MTS, infine, se un CU utilizza la modalità di codifica ISP,
questo (il flag) sarà settato a 0 e non sarà inviato al decoder. Dunque, l’encoder non farà test RD per
le diverse trasformate disponibili per ogni sotto-partizione risultante. La scelta della trasformata per
la modalità ISP sarà invece fissa e selezionata secondo la modalità intra, l’ordine di processing e la
grandezza dei blocchi utilizzati, quindi non è richiesto alcun tipo di segnalazione. Ad esempio,
siano to e tv le trasformate orizzontali e verticali selezionate rispettivamente per le sotto-partizioni
LxA, dove L è la larghezza ed A è l’altezza, allora, la trasformata è selezionata secondo le seguenti
regole: se L = 1 o A = 1, allora non c’è trasformata orizzontale o verticale; se L = 2 o L > 32, to =
DCT-II, se A=2 o A>32, tv = DCT-II, altrimenti la trasformata viene scelta come dalla tabella di
seguito:

Modalità Intra to tv
Planar
DST-VII DST-VII
Ang. 31,32,34,36,37
DC
DCT-II DCT-II
Ang. 33, 35
Ang. 2, 4, 6…28,30
DST-VII DCT-II
Ang. 39,41,43…63,65
Ang. 3,5,7…27,29
DCT-II DST-VII
Ang. 38,40,42…64,66
Selezione della Trasformata a seconda della modalità intra

Nella modalità ISP, tutte e 67 le modalità intra sono consentite. Il PDPC viene applicato anche se la
larghezza e l’altezza corrispondenti sono lunghe almeno 4 sample, inoltre, la condizione per la
selezione del filtro di interpolazione intra non esiste più e viene sempre applicato un filtro cubico
DCT-IF per l’interpolazione delle posizioni frazionarie.

- MIP – Matrix Weighted Intra Prediction

L’MIP (Matrix Weighted Intra Prediction) è una nuova tecnica di predizione intra aggiunta
nell’H.266. Per predire i sample di un blocco rettangolare di larghezza L ed altezza A, l’MIP prende
una linea dei sample confinanti vicini ricostruiti a sinistra del blocco ed una linea di L sample
confinanti vicini ricostruiti sopra al blocco come input. Se i sample riscotruiti non sono disponibili,
questi vengono generati così come viene fatto nella predizione intra convenzionale. La generazione
del segnale di predizione è basata su 3 step: media, moltiplicazione dei vettori matrice ed
interpolazione lineare.
Processo di IMP (Matrix Weighted Intra Prediction)

Step 1 - Media dei sample vicini

Tra i sample vicini, vengono selezionati 4 od 8 sample facendo la media sulla base della grandezza
e della forma del blocco. In particolare, i confinanti di input “confinante superiore” e l’altro
“confinante” sono ridotti a confinanti più piccoli detti “confinante superiore ridotto” e “confinante
ridotto” facendo la media dei sample vicini confinanti usando delle regole predefinite a seconda
della grandezza del blocco, dopodiché, i due confinanti ridotti sono concatenati in un vettore
confinante ridotto chiamato “confinante ridotto” che è dunque di grandezza 4 per i blocchi da 4x4 e
di grandezza 8 per i blocchi di tutte le altre forme.

Step 2 – Moltiplicazione di matrice

La moltiplicazione dei vettori di matrice, seguita da un’addizione di un offset, viene eseguita dopo
che è stata eseguita la media dei sample in quanto il risultato di quella operazione sarà il nostro
input. Il risultato di questo è un segnale di predizione ridotto su un set sotto-campionato di sample
nel blocco originale. Dal vettore input ridotto chiamato “confinante ridotto” viene generato un
segnale di predizione ridotto detto “predizione ridotta”, che è un segnale sul blocco sotto-
campionato di larghezza Lridotta ed altezza Aridotta definiti come:

Lridotta = { 4 per massimo (L, A) <= 8 }


{minimo(L, 8) per massimo (L, A) > 8 }

Aridotta = { 4 per massimo (L, A) <= 8 }


{minimo(A, 8) per massimo (L, A) > 8 }

Il segnale di predizione ridotto predred è computato calcolando il prodotto di vettore di matrice ed


aggiungendo un offset:

predred = A * confinanteridotto + b

dove A è una matrice che ha le righe Lridotta * Aridotta e 4 colonne se L = A = 4 oppure 8 colonne in
tutti gli altri casi e b è un vettore di grandezza Lridotta * Aridotta. La matrice A ed il vettore di
offset b sono presi da uno degli insiemi S0, S1, S2.
Uno definisce un index idx = idx (L, A) come:

{0 per L = A = 4 }
idx (L, A) = { 1 per massimo (L, A) = 8 }
{1 per massimo (L, A) > 8 }

In questo caso abbiamo i coefficienti della matrice A rappresentati con precisione ad 8bit.
L’insieme S0 consiste in 16 matrici:

ognuna con 16 righe e 4 colonne e 16 vettori di offset:

ognuni di grandezza 16.


Le matrici ed i vettori di offset di quell’insieme sono usati per i blocchi di grandezza 4x4.
L’insieme S1 consiste in 8 matrici:

ognuna con 16 righe ed 8 colonne ed 8 vettori di offset:

ognuno di grandezza 16.


L’insieme S2 consiste in 6 matrici:

ognuna con 64 righe ed 8 colonne e 6 vettori di offset:

di grandezza 64.

Step 3 – Interpolazione

Il segnale di predizione alle posizioni rimanenti è generato dal segnale di predizione sull’insieme
sotto-campionato dall’interpolazione lineare ed in particolare si tratta di un’interpolazione lineare a
singolo step in ogni direzione. L’interpolazione viene prima fatta nella direzione orizzontale e poi su
quella verticale a prescindere dalla forma o dalla grandezza del blocco.

- Segnalazione della modalità MIP ed armonizzazione con gli altri strumenti di codifica

Nella modalità intra, per ogni CU (Coding Unit), viene inviato un flag che indica se la modalità
MIP è applicata o meno. Se viene applicata la modalità MIP, allora viene segnalato dal flag e, per
una modalità MIP, vengono derivati due flag: quello di trasposta – che determina se la modalità è
trasposta – e quello di ID, che determina quale matrice usare per una data modalità MIP. La
modalità di codifica MIP è armonizzata con gli altri strumenti di codifica; l’LFNST è abilitato per
l’MIP sui blocchi grandi evengono utilizzati trasformate LFNST di modalità planar. La derivazione
dei sample di riferimento per l’MIP è fatta esattamente come per le modalità di predizione intra
convenzionali. Per lo step di up-sampling usato nella predizione MIP, vengono utilizzati i sample di
riferimento originali invece di quelli sotto-campionati ed il clipping viene fatto prima dell’up-
sampling e non dopo. L’MIP è consentito fino ad un massimo di 64x64 a prescindere dalla
grandezza massima di trasformata ed il numero di modalità MIP è 32 per sizeID = 0, 16 per sizeID
= 1 e 12 per sizeID = 2.

- Predizione Inter

Per ogni CU predetto inter vengono utilizzati i parametri di spostamento che consistono nei vettori
spostamento, gli indici di riferimento di immagine e gli index di utilizzo delle liste di riferimento di
immagine, assieme ad altre informazioni. Il parametro di spostamento può essere segnalato in
maniera esplicita od implicita. Quando un CU è codificato con la modalità skip, il CU è associato
con un PU e non ha coefficienti residui significativi, nessuna delta di vettore spostamento o index di
riferimento di immagine. Viene specificata una modalità “merge” in cui i parametri di spostamento
per il CU corrente sono ottenuti dai CU vicini (confinanti), inclusi i candidati spaziali e temporali,
così come altre cose introdotte nell’H.266. La modalità merge può essere applicata a qualsiasi CU
predetto inter, non solo alla modalità skip. L’alternativa alla modalità “merge” è la trasmissione
esplicita dei parametri di spostamento, in cui il vettore spostamento, l’index di riferimento di
immagine corrispondente per ogni lista di immagini di riferimento e la lista di riferimento di
immagini (assieme ad altre cose) vengono segnalate esplicitamento per ogni CU. Oltre alle feature
della codifica inter dell’H.265, l’H.266 include una serie di strumenti di predizione inter nuovi o
migliorati, ovvero: la Merge Prediction Estesa, la Merge Mode MVD, la segnalazione MVD
Simmetrica (SMVD – Symmetric MVD Signalling), la predizione moto-compensata affine, la
predizione di vettori spostamento temporale basata sui sotto-blocchi, la risoluzione di vettori
spostamento adattiva, il salvataggio dei motion field (1/16 di sample di luma MV e compressione di
motion field 8x8), Bi-Prediction con peso a livello di CU, Bi-Directional Optical Flow, refinement
dei vettori spostamento lato decoder, la modalità di partizione geometrica ed infine le predizioni
combinate inter ed intra.

- Merge Prediction Estesa

Nell’H.266, la lista dei candidati di merge è costruita includendo i seguenti 5 tipi di candidati:

1) MVP spaziale dai CU vicini (confinanti) nello spazio


2) MVP temporale dai CU collocati
3) MVP basati sulla storia dalla tabella FIFO
4) media di coppia MVP
5) MV zero

La grandezza della lista di merge è segnalata nell’header e la grandezza massima consentita è 6. Per
ogni codice CU nella modalità merge, viene encodato un index del miglior candidato di merge
usando la binarizzazione TU (Truncated Unary). Il primo bin dell’index di merge è codificato col
contesto e viene utilizzata la codifica bypass per gli altri bin. Così come per l’H.265, anche l’H.266
supporta la derivazione parallela delle liste di candidati di merge per tutti i CU all’interno di un’area
di una certa grandezza.

- Derivazione dei Candidati Spaziali

La derivazione dei candidati di merge spaziali nell’H.266 è la stessa dell’H.265, tranne che per la
posizione dei primi due candidati di merge che sono invertiti. Un massimo di 4 candidati di merge
sono selezionati tra i candidati situati nelle posizioni illustrate di seguito:
Posizioni dei candidati di merge spaziali

L’ordine di derivazione è B0, A0, B1, A1 e B2. La posizione B2 è considerata solo quando uno o più
di 1 CU di posizione B0, A0, B1, A1 non sono disponibili (ad esempio perché appartengono ad un
altro slice o tile) o sono codificati intra. Dopo che è stato aggiunto il candidato in posizione A1,
l’aggiunta dei candidati rimanenti è soggetto ad un controllo di ridondanza che assicura che i
candidati con le stesse informazioni di spostamento siano esclusi dalla lista in modo che la codifica
sia più efficiente, tuttavia, per ridurre il costo computazionale, non vengono considerate tutte le
possibili coppie candidate.

- Derivazione dei Candidati Temporali

In questa fase, solamente un candidato viene aggiunto alla lista. In particolare, nella derivazione di
questo candidato di merge temporale, viene derivato un vettore spostamento scalato basato sul CU
appartenente all’immagine di riferimento. La lista dell’immagine di rfierimento usata per la
derivazione del CU è segnalata esplicitamente nell’header ed il vettore spostamento scalato per il
candidato di merge temporale è ottenuto come mostrato nell’immagine di seguito:

Scaling del vettore spostamento per il candidato di merge temporale


Il vettore spostamento scalato per il candidato di merge temporale è ottenuto dalla linea tratteggiata,
che è scalata dal vettore spostamento del CU usando le distanze POC, tb e td, dove tb è definito
come la differenza POC tra l’immagine di riferimento e quella corrente e td è definito come la
differenza POC tra l’immagine di riferimento e l’immagine, mentre l’index è posto uguale a 0. La
posizione per il candidato temporale è selezionata tra i candidati C0 e C1 come mostrato di seguito:

Posizioni candidate per il candidato di merge temporale, C0 e C1

Se il CU alla posizione C0 non è disponibile, è codificato intra, oppure è fuori dalla riga corrente del
CTU, allora è utilizzata la posizione C1, altrimenti, viene utilizzata la posizione C0.

- Derivazione dei candidati di merge basata sulla storia

I candidati di merge MVP basati sulla storia sono aggiunti alla lista di merge dopo l’MVP spaziale
ed il TMVP. In questo metodo, le informazioni di spostamento del blocco precedentemente
codificato sono salvate in una tabella ed utilizzate come MVP per il CU corrente. La tabella con più
candidati HMVP è mantenuta durante il processo di encoding/decoding. La tabella è resettata (cioè
viene svuotata) quando viene incontrata una nuova riga CTU. Ogni volta che abbiamo un non sotto-
blocco CU codificato intra, le informazioni di spostamento associate sono aggiunte all’ultima entry
della tabella come nuovo candidato HMVP. La grandezza S della tabella HMVP è settata a 6, il che
vuol dire che fino a 6 candidati MVP basati sulla storia possono essere aggiunti. Quando viene
inserito un nuovo candidato di spostamento alla tabella, viene utilizzata una regola FIFO (First In
First Out) in cui viene applicato un controllo di ridondanza per sapere se ci sono HMVP identici
nella tabella. Se vengono trovati HMVP identici, questi vengono rimossi dalla tabella e tutti i
candidati HMVP dopo vengono portati avanti. Gli ultimi candidati HMVP nella tabella sono
controllati in ordine ed inseriti nella lista dei candidati dopo il candidato TMVP. Il controllo di
ridondanza è applicato ai candidati HMVP, ma, per ridurre il numero di operazioni di controllo,
vengono applicate 2 semplificazioni: la prima è che il numero di candidati HMPV usato per la
generazione della lista di merge è settato come:

(N <= 4 ) ? M: (8 − N)

dove N indica il numero di candidati esistenti nella lista di merge ed M indica il numero di candidati
HMVP disponibili nella tabella.
La seconda è che una volta che il numero totale di candidati di merge disponibili raggiunga il
numero massimo di candidati di merge consentito -1, il processo di costruzione della lista di
candidati di merge dall’HMVP è terminato.

- Derivazione dei candidati di merge secondo la media di coppia

I candidati secondo la media di coppia sono generati facendo la media delle coppie predefinite dei
candidati nella lista dei candidati di merge esistenti e le coppie predefinite sono definite come:

{(0, 1), (0, 2), (1, 2), (0, 3), (1, 3), (2, 3)}

dove i numeri denotano gli indici di merge alla lista dei candidati di merge. I vettori spostamento
sottoposti a media sono calcolati separatamente per ogni lista di riferimento. Se entrambi i vettori
spostamento sono disponibili in una lista, questi vengono sottoposti a media anche quando puntano
a diverse immagini di riferimento; se solamente un vettore spostamento è disponibile, invece, viene
usato direttamente, altrimenti, se non ci sono vettori spostamento, la lista è invalida. Quando la lista
di merge non è completa dopo che sono stati aggiunti i candidati di merge secondo la media di
coppia, sono inseriti degli MVP 0 in coda finché non viene raggiunto il numero massimo di
candidati di merge.

- Regione della stima di merge

La regione della stima di merge, anche detta MER (Merge Estimation Region) consente la
derivazione indipendente della lista dei candidati di merge per i CU nella stessa regione di stima di
merge, MER (Merge Estimation Region). Un blocco candidato che è all'interno della stessa MER
(Merge Estimation Region) del CU corrente non è incluso per la generazione della lista dei
candidati di merge per il CU corrente. Inoltre, il processo di updating per la lista del vettore
spostamento basata sulla storia del candidato di predizione è aggiornato solo se:

(xCb + cb Larghezza) >> Log2ParMrgLevel è più grande di (xCb >> Log2ParMrgLevel)

(yCb + cb Altezza) >> Log2ParMrgLevel è più grande di (yCb >> Log2ParMrgLevel)

e dove (xCb, yCb) è la posizione del sample di luma superiore sinistro del CU corrente
nell'immagine e (cb Larghezza, cb Altezza) è la grandezza del CU. La grandezza della MER (Merge
Estimation Region) è selezionata lato encoder e viene segnalata come:

log2_parallel_merge_level_minus2

- Modalità di merge con MVD

Oltre alla modalità di merge, in cui le informazioni di spostamento implicitamente derivate sono
usate direttamente per la generazione dei sample di predizione del CU corrente, la modalità merge
con MVD (Motion Vector Differences) è totalmente nuova e caratteristica dell'H.266. Il flag
MMVD (Merge Mode con Motion Vector Differences) è segnalato subito dopo aver mandato il flag
skip ed il flag merge per specificare se viene usata questa nuova modalità per un CU. Nella MMVD
(Merge Mode con Motion Vector Differences), uno dei primi 2 candidati nella lista di merge viene
scelto per essere usato come base MV.
Il flag del candidato di merge è segnalato per specificare quale viene usato. Gli index di distanza
vengono utilizzati per specificare le informazioni di magnitudine di spostamento ed indicare l'offset
predefinito dal punto di partenza. Un offset è aggiunto alla componente orizzontale od alla
componente verticale del MV di partenza.

Punti di ricerca MMVD (Merge Mode con Motion Vector Differences)

La relazione tra l'index di distanza e l'offset predefinito è:

Index di Distanza 0 1 2 3 4 5 6 7
Offset
1/4 1/2 1 2 4 8 16 32
(in sample di luma)

L'index di direzione rappresenta la direzione delle MVD (Motion Vector Differences) relativa al
punto di partenza. L'index di direzione può rappresentare una delle direzioni seguenti:

Index di Direzione 00 01 10 11
Asse x + − N/A N/A
Asse y N/A N/A + −

Il significato del segno delle MVD (Motion Vector Differences) può variare a seconda delle
informazioni del MV di partenza. Quando il MV di partenza è una mono-predizione MV o una bi-
predizione MV con entrambe le liste che puntano allo stesso lato dell'immagine corrente (cioè i
POC dei due riferimenti sono entrambi più grandi o più piccoli del POC dell'immagine corrente),
allora il segno della tabella di sopra rappresenta il segno dell'offset MV aggiunto al MV di partenza.
Quando il MV di partenza è una bi-predizione con due MV che puntano a lati diversi dell'immagine
corrente (cioè il POC di un riferimento è più grande del POC dell'immagine corrente ed il POC
dell'altro riferimento è più piccolo del POC dell'immagine corrente), allora il segno nella tabella di
sopra specifica il segno dell'offset MV aggiunto al componente MV della lista 0 del MV di partenza
ed il segno del MV della lista 1 ha il segno opposto.

- Codifica MVD Simmetrica

Nell'H.266, oltre alla segnalazione della modalità MVD (Motion Vector Differences) per la
predizione unidirezionale (mono-direzionale) normale e bi-direzionale, viene segnalata anche la
modalità MVD (Motion Vector Differences) simmetrica. Nella modalità MVD (Motion Vector
Differences) simmetrica, le informazioni di spostamento, inclusi gli indici di riferimento
dell'immagine sia della lista 0 che della lista 1 non vengono segnalati, ma bensì derivati. Il processo
di decodifica della modalità MVD simmetrica può essere descritto in due fasi. Nella prima fase, a
livello di slice, le variabili BiDirPredFlag, RefIdxSymL0 e RefIdxSymL1 sono derivate secondo
queste condizioni: se mvd_l1_zero_flag è 1, allora BiDirPredFlag è posto uguale 0, altrimenti, se
l'immagine di riferimento più vicina nella lista 0 e l'immagine di riferimento più vicina nella lista 1
formano un paio di immagini di riferimento forward e backward oppure al contrario (cioè backward
e forward), allora BiDirPredFlag è posto ad 1 e le immagini di riferimento sia della lista 0 che della
lista 1 sono immagini di riferimento a corto termine (sennò BiDirPredFlag è posto a 0). Nella
seconda fase, a livello di CU, un flag di modalità simmetrica – che indica se questa viene usata o
meno – è segnalato esplicitamente se il CU è codificato con la bi-predizione e BiDirPredFlag è
uguale ad 1. Quando il flag di modalità simmetrica è su "true", solamente mvp_l0_flag,
mvp_l1_flag ed MVD0 sono segnalati esplicitamente. Gli indici di riferimento per la lista 0 e la
lista 1 sono posti uguale alla coppia di immagini di riferimento e l'MVD1 è posto uguale a -MVD0.

Illustrazione della modalità MVD simmetrica

Nell'encoder, la stima di spostamento MVD simmetrica inizia con la valutazione MV iniziale.


L'insieme dei candidati MV comprende i MV ottenuti dalla ricerca uni-direzionale
(monodirezionale), i MV ottenuti dalla ricerca bi-prediction ed i MV ottenuti dalla lista AMVP e,
quello con il costo rate-distortion minore, viene scelto per essere il MV iniziale per la ricerca di
spostamento MVD simmetrica.
- Predizione moto-compensata affine

Nell'H.265, solamente il modello di traslazione di spostamento veniva applicato per la predizione di


moto-compensazione (MCP – Motion Compensation Prediction), ma nel mondo reale ci sono tanti
tipi di spostamento, ad esempio degli zoom in e zoom out, delle rotazioni, dei cambi di prospettiva
ed altri tipi di spostamento irregolari. Nell'H.266, viene applicata una predizione moto-compensata
affine basata sui blocchi ed il campo di spostamento affine del blocco è descritto dalle informazioni
di spostamento dei 2 o 3 punti di controllo (4 o 6 parametri).

Modello affine a 4 parametri (2 p. di controllo) - Modello affine a 6 parametri (3 p. di controllo)

Per il modello di spostamento affine a 4 parametri, il vettore spostamento alla posizione di sample
(x, y) in un blocco è derivato come:

Per il modello di spostamento affine a 6 parametri, il vettore spostamento alla posizione di sample
(x, y) in un blocco è derivato come:
dove (mv0x, mv0y) è il vettore spostamento del punto di controllo dell'angolo superiore sinistro,
(mv1x, mv1y) è il vettore spostamento del punto di controllo dell'angolo superiore destro ed (mv2x,
mv2y) è il vettore spostamento del punto di controllo dell'angolo inferiore sinistro. Per semplificare
la predizione di moto-compensazione, viene applicata la predizione di trasformata affine basata sui
blocchi. Per derivare il vettore spostamento di ogni sotto-blocco da 4x4 di luma, il vettore
spostamento del sample centrale di ogni ogni sotto-blocco viene calcolato usando l'equazione di
sopra e viene poi arrotondato ad 1/16 di accuratezza, dopodiché vengono applicati i filtri di
interpolazione per generare la predizione di ogni sotto-blocco con il vettore spostamento derivato.
La grandezza del sotto-blocco delle componenti di chroma è anch'esso posto a 4x4 ed il MV di un
sotto-blocco di chroma da 4x4 viene calcolato come la media dei MV dei 4 sotto-blocchi di luma
corrispondenti da 4x4.

MVF affine per sotto-blocco

Così come avevamo visto per la predizione di spostamento inter moto-traslazionale, anche in questo
caso abbiamo 2 modalità di predizione di spostamento inter affine: la modalità merge affine e la
modalità AMVP affine.

- Predizione Merge Affine

La modalità AF_MERGE può essere applicata per i CU con larghezza ed altezza maggiori o uguali
ad 8. In questa modalità i CPMV dei CU correnti sono generati sulla base delle informazioni di
spostamento dei CU vicini (confinanti) nello spazio. Ci possono essere fino a 5 candidati CPMVP e
viene segnalato un index per indicare quello da usare per il CU corrente. Vengono utilizzati 3 tipi di
candidati CPVM per formare la lista di candidati di merge affine: candidati di merge affine ereditati
estrapolati dai CPMV dei CU vicini (confinanti), candidati di merge affine costruiti CPMVP che
sono derivati usando i MV traslazionali dei CU vicini (confinanti), MV zero. Nell'H.266 ci sono al
massimo 2 candidati affini ereditati, che sono derivati dal modallo di spostamento affine dei blocchi
vicini (confinanti) uno dal CU vicini (confinanti) a sinistra ed uno dai CU vicini (confinanti) sopra.
I blocchi candidati sono:

Per il predittore sinistro, l'ordine di scansione è A0 -> A1 e per il predittore superiore l'ordine di
scansione è B0 -> B1 -> B2. Solamente il primo candidato ereditato di ogni lato viene selezionato e
non viene effettuato alcun controllo di ridondanza tra i due candidati ereditati. Quando un CU affine
confinante è identificato, i suoi vettori spostamento (punti di controllo) sono usati per derivare il
candidato CPMVP nella lista di merge affine del CU corrente.

Come mostrato nell'immagine qua sopra, se il blocco confinante inferiore sinistro A è codificato in
modalità affine, i vettori spostamento v2, v3 e v4 dell'angolo superiore sinistro, dell'angolo superiore
destro e dell'angolo inferiore sinistro del CU che contiene il blocco A sono raggiunti. Quando il
blocco A è codificato con un modallo affine a 4 parametri, i 2 CPMV del CU corrente sono calcolati
secondo v2 e v3. Nel caso in cui il blocco A fosse codificato con un modello affine a 6 parametri,
invece, i 3 CPMV del CU corrente sono calcolati secondo v2, v3 e v4. Il candidato affine costruito
significa che il candidato è costruito combinando le informazioni di spostamento traslazionale di
ogni punto di controllo. Le informazioni di spostamento per i punti di controllo sono derivate dai
vicini spaziali e temporali specificati.
Posizioni candidate per la modalità di merge affine costruita

CPMVk (k=1, 2, 3, 4) rappresenta il punto di controllo k-esimo. Per CPMV1, sono controllati i
blocchi B2 -> B3 -> A2 e viene usato il MV del primo blocco disponibile. Per CPMV2, sono
controllati i blocchi B1 -> B0 e per CPMV3 sono controllati i blocchi A1 -> A0, mentre per CPMV4,
viene usato il TMVP (se è disponibile). Una volta raggiunti i MV dei 4 punti di controllo, i
candidati di merge affine sono costruiti sulla base di queste informazioni di spostamento. Vengono
utilizzate in ordine le seguenti combinazioni di punti di controllo MV:

{CPMV1, CPMV2, CPMV3}, {CPMV1, CPMV2, CPMV4},


{CPMV1, CPMV3, CPMV4},{CPMV2, CPMV3, CPMV4},
{ CPMV1, CPMV2}, { CPMV1, CPMV3}

La combinazione di 3 CPMV costruisce un candidato di merge affine a 6 parametri e la


combinazione di 2 CPMV costruisce un candidato di merge affine a 4 parametri. Per evitare il
processso di motion scaling, se gli indici di riferimento dei punti di controllo sono diversi, la
combinazione di punti di controllo MV ad essi associata viene dimenticata. Una volta che i
candidati di merge affine ereditati e costruiti sono controllati, se la lista non è ancora piena,
vengono aggiunti MV zero alla fine della stessa.

- Predizione AMVP Affine

La modalità AMVP affine può essere applicata per i CU con sia larghezza che altezza maggiori (o
uguali) a 16. Viene segnalato un flag affine a livello di CU nel bitstream per indicare se la modalità
AMVP affine è usata e poi viene segnalato un altro flag per indicare se si tratta della modalità affine
a 4 parametri od a 6 parametri. In questa modalità, la differenza dei CPMV del CU corrente ed i
loro predittori CPMVP sono segnalati nel bitstream.
La grandezza della lista di candidati AVMP affine è 2 ed è generata usando i seguenti 4 tipi di
candidati CPVM:

1) Candidati AMVP affini ereditati estrapolati dai CPMV dei CU vicini.


2) Candidati AMVP affini costruiti CPMVP che sono derivati usando i MV traslazionali dei CU
vicini
3) MV traslazionali dai CU vicini
4) MV zero

L'ordine di controllo dei candidati AMVP affini ereditati è lo stesso di quello dei candidati di merge
affine ereditati; l'unica differenza è che, per i candidati AVMP, solo il CU affine che ha la stessa
immagine di riferimento nel blocco corrente viene considerato. Per quanto riguarda il controllo di
ridondanza, questo non viene effettuato quando viene inserito un predittore di spostamento affine
ereditato nella lista di candidati. Per quanto riguarda l'ordine di controllo, viene usato lo stesso che
viene usato nella costruzione dei candidati di merge affine. Inoltre, viene controllato anche l'index
di immagine di riferimento del blocco vicino e viene usato il primo blocco nell'ordine di controllo
che è codificato inter ed ha la stessa immagine di riferimento nel CU corrente. Quando il CU
corrente è codificato nella modalità affine a 4 parametri ed mv0 ed mv1 sono entrambi disponibili,
questi sono aggiunti come candidato nella lista AMVP affine, altrimenti, il candidato AMVP
costruito viene settato come non "non disponibile". Se la lista dei candidati AMVP affini è ancora
inferiore a 2 dopo che sono stati controllati i candidati AMVP costruiti ed anche affini ereditati,
sono aggiunti mv0, mv1 ed mv2, in ordine, come MV traslazionali per predire tutti i punti di
controllo MV del CU corrente, se disponibili. Infine, se ancora non siamo arrivati a completare la
lista, vengono utilizzati gli MV zero per riempire la lista AMVP affine.

- Salvataggio delle informazioni di spostamento affine

Nell'H.266, i CPMV dei CU affini sono salvate in un buffer separato. I CPMV salvati sono usati
solamente per generare i CPMVP ereditati nella modalità di merge affine e la modalità AMVP
affine per i CU codificati successivamente. I sotto-blocchi MV derivati dai CPMV sono usati per la
moto-compensazione, per la derivazione MV della lista di merge/AMVP dei MV translazionali e
per il de-blocking. Per evitare il picture line buffer per i CPMV addizionali, l'ereditarietà dei dati di
spostamento affine dai CU dei CTU superiori è trattata in maniera differente rispetto all'ereditarietà
dai semplici CU vicini. Se il candidato CU per l'ereditarietà dei dati di spostamento affine è nella
linea CTU superiore, vengono utilizzati i sotto-blocchi MV inferiore sinistro ed inferiore destro nel
line buffer invece dei CPMV per la derivazione affine MVP. In questo modo, i CPMV sono salvati
solamente nel buffer locale. Se il CU candidato è codificato con la codifica affine a 6 parametri, il
modello affine è degradato ad un modello a 4 parametri. Assieme ai confini CTU superiori, anche i
sotto-blocchi di vettori spostamento inferiore sinistro e destro di un CU vengono utilizzati per
l'ereditarietà affine dei CU nei CTU inferiori.
Illustrazione dell'utilizzo dei vettori spostamento

- Raffinamento della predizione con l'optical flow per la modalità affine

La moto-compensazione affine basata sui sotto-blocchi può ridurre la complessità computazionale e


la banda di accesso in memoria rispetto alla moto-compensazione basata sui pixel al costo
dell'accuratezza di predizione. Per raggiungere una migliore granularità per la moto-
compensazione, viene utilizzato il raffinamento della predizione con l'optical flow per raffinare
appunto la predizione moto-compensata affine basata sui sotto-blocchi senza aumentare la banda di
accesso della memoria per la moto-compensazione. Nell'H.266, una volta che la moto-
compensazione affine basata sui sotto-blocchi è effettuata, i sample di predizione del luma sono
raffinati aggiungendo una differenza derivata dall'equazione di optical flow. Questo processo può
essere descritto in 4 step:

1) Viene effettuata la moto-compensazione affine basata sui sotto-blocchi per generare la predizione
I(i, j)

2) I gradienti spaziali gx(i, j) e gy(i, j) della predizione dei sotto-blocchi sono calcolati ad ogni
posizione dei sample usando un filtro a 3 tap [-1, 0, 1]. Il calcolo del gradiente è esattamente lo
stesso di quello del BDOF:

gx(i, j) = (I(i+1, j) > shift 1) – (I(i-1, j) > shift 1


gy(i, j) = (I(i, j+1) > shift 1) – (I(i, j-1) > shift 1

dove "shift 1" è usato per controllare la precisione del gradiente. Il sotto-blocco di predizione (4x4)
è esteso di un sample su ogni lato per il calcolo del gradiente. Per evitare ulteriore banda di
memoria ed un'altra computazione di interpolazione, questi sample estesi sui bordi estesi vengono
copiati dalla posizione di pixel intera più vicina nell'immagine di riferimento.

3) Il raffinamento della predizione del luma è calcolato usando l'equazione di Optical Flow:

ΔI(i,j) = gx(i,j)+gy(i,j) * Δvy(i,j)


dove Δv(i,j) è la differenza tra i sample MV computati per la posizione di sample (i,j), denotata da
v(i,j) ed il sotto-blocco MV del sotto-blocco a cui appartiene il sample (i,j).

Sotto-blocco MV VSB e pixel Δv(i,j) - mostrato come freccia rossa

Δv(i,j) è quantizzato in unità di 1/32 sample di luma. Visto che i parametri del modello affine e la
posizione del sample relativa al centro del sotto-blocco non sono cambiate da sotto-blocco a sotto-
blocco, Δv(i,j) può essere calcolato per il primo sotto-blocco e riutilizzato per altri sotto-blocchi
nello stesso CU. Siano dx(i,j) e dy(i,j) gli offset orizzontale e verticale dalla posizione del sample
(i,j) al centro del sotto-blocco (xSB, ySB), allora Δv(x,y) può essere derivato usando:

{ dx(i,j) = i - xSB
{ dy(i,j) = j -ySB

{Δvx(i,j) = C * dx(i,j) + D * dy(i,j)


{Δvy(i,j) = E * dx(i,j) + F * dy(i,j)

Per mantenere l'accuratezza, l'entrata del sotto-blocco (xSB, ySB) è calcolata come:

[(WSB – 1)/2, (HSB – 1)/2]

dove WSB ed HSB sono i sotto-blocchi Width (Larghezza) ed Height (Altezza).


Per il modello affine a 4 parametri, abbiamo:
mentre per il modello affine a 6 parametri, abbiamo:

dove (v0x, v0y), (v1x, v1y), (v2x, v2y) sono i vettori spostamento dei punti di controllo superiore
sinistro, superiore destro ed inferiore sinistro, mentre w ed h sono Width ed Height, cioè la
Larghezza e l'Altezza del CU.

4) Come ultimo step, il raffinamento della predizione del luma ΔI(i,j) è aggiunto al sotto-blocco di
predizione I(i,j). La predizione finale I' è generata da:

I'(i,j) = I(i,j) + ΔI(i,j)

Il raffinamento della predizione con l'Optical Flow non è applicato in 2 casi per i CU con la codifica
affine: se tutti i punti di controllo MV sono gli stessi, il che vuol dire che il CU ha solo spostamento
translazionale, oppure se i parametri di spostamento affine sono più grandi di un limite specificato
perché la moto-compensazione affine basata sui sotto-blocchi è degradata a moto-compensazione
basata sui CU per evitare grandi requisiti di banda per l'accesso in memoria. Nel raffinamento della
predizione con l'Optical Flow viene inoltre applicato un metodo di encoding veloce per ridurre la
complessità di encoding della stima di spostamento affine. Questo comunque non viene applicato
nella fase di stima di spostamento affine in due situazioni: o se il CU non è il blocco radice ed il suo
blocco padre non ha scelto la modalità affine come sua modalità ideale, oppure se la magnitudine
dei 4 parametri affine C, D, E, F è minore di un threshold predefinito e l'immagine corrente non è
un'immagine a basso delay (perché il miglioramento dato dall'utilizzo di questo tipo di predizione
sarebbe minimo).

- Predizione temporale coi vettori spostamento basata sui sotto-blocchi

L'H.266 supporta il metodo di predizione temporale coi vettori spostamento basata sui sotto-blocchi
detto SbTMVP. In maniera simile alla predizione temporale coi vettori spostamento dell'H.265 detta
TMVP, la SbTMVP dell'H.266 utilizza i field di spostamento nell'immagine collocata per migliorare
la predizione dei vettori spostamento e la modalità merge per i CU nell'immagine corrente. La
stessa immagine collocata usata dal TMVP viene usata anche per SbTVMP, ma ci sono delle
differenze tra i due: mentre il TMVP predice lo spostamento a livello di CU, l'SbTMVP lo fa a
livello di sotto-CU. Inoltre, mentre il TMVP fa il fetch temporale dei vettori spostamento dal blocco
collocato nell'immagine collocata (il blocco collocato è il blocco inferiore destro o centrale relativo
al CU corrente), l'SbTMVP applica un motion shift prima di fare il fetch delle informazioni di
spostamento temporale dall'immagine collocata e, questo (il motion shift), è ottenuto dal vettore
spostamento di uno dei blocchi vicini nello spazio del CU corrente.
Blocchi vicini nello spazio usati dall'ATVMP

L'SbTMVP predice i vettori spostamento dei sotto-CU all'interno del CU attuale in 2 step. Nel
primo step, viene esaminato il vicino nello spazio A1. Se A1 ha un vettore spostamento che utilizza
l'immagine collocata come sua immagine di riferimento, allora questo vettore spostamento viene
selezionato per essere il motion shift che verrà applicato. Se non viene identificato questo
spostamento, allora il motion shift è settato a (0,0). Nel secondo step, viene applicato il motion shift
che era stato identificato nel primo step (cioè viene aggiunto alle coordinate del blocco corrente) per
ottenere le informazioni di spostamento a livello di sotto-CU (cioè i vettori spostamento e gli indici
di riferimento) dall'immagine collocata.

Derivazione del field spostamento sotto-CU applicando un motion shift dal vicino nello spazio
e scalando l'informazione di spostamento dal sotto-CU collocato corrispondente
Nell'esempio dell'immagine di sopra, il motion shift è lo spostamento del blocco A1, dopodiché, per
ogni sotto-CU, viene usata l'informazione di spostamento o il suo blocco corrispondente (la griglia
di spostamento più piccola che copre il sample centrale) nell'immagine collocata per derivare le
informazioni di spostamento del sotto-CU. Dopo che l'informazione di spostamento del sotto-CU
collocato è stata identificata, questa viene convertita in vettori spostamento ed indici di riferimento
del sotto-CU corrente in maniera simile a quella del TMVP dell'H.265 in cui viene applicato lo
scaling di spostamento temporale per allineare le immagini di riferimento dei vettori di spostamento
temporale a quelli del CU corrente. Nell'H.266, viene usata una lista di merge combinata basata sui
sotto-blocchi che contiene sia il candidato SbTVMP che i candidati di merge affine per segnalare la
modalità di merge basata sui sotto-blocchi. La modalità SbTVMP è abilitata o disabilitata da un flag
SPS (Sequence Parameter Set). Se la modalità SbTMVP è abilitata, il predittore SbTMVP è
aggiunto come prima entry della lista di candidati di merge basata sui sotto-blocchi e seguito dai
candidati di merge affine. La grandezza della lista di merge basata sui sotto-blocchi è segnalata in
un SPS e la grandezza massima consentita della lista di merge basata sui sotto-blocchi è 5. La
grandezza del sotto-CU usato nell'SbTMVP è fissata ad 8x8, e, così come per la modalità di merge
affine, la modalità SbTMVP è applicabile solo al CU con sia larghezza che altezza maggiori o
uguali ad 8. La logica di encoding dei candidati di merge SbTMVP addizionali è la stessa degli altri
candidati di merge, ovvero, per ogni CU in uno slice P o B, viene fatto un controllo di ridondanza
aggiuntivo per decidere se usare il candidato SbTMVP o meno.

- Risoluzione di Vettori Spostamento Adattiva

Nell'H.265, le differenze di spostamento vettoriale, dette MVD, sono le differenze tra il vettore
spostamento ed il vettore spostamento predetto di un CU e vengono segnalate in unità di quarti di
sample di luma quando il flag di utilizzo di MV intero use_integer_mv_flag è posto a 0 nell'header
dello slice. Nell'H.266, viene introdotto uno schema di risoluzione di vettori spostamento adattivo a
livello di CU detto AMVR e, questo nuovo schema, permette agli MVD dei CU di essere codificati
con precisione differente. A seconda della modalità (AMVP normale o affine) per il CU corrente,
l'MVD del CU corrente possono essere selezionati in maniera adattiva. Nella modalità AMVP
normale, è possibile scegliere un quarto di sample di luma, metà sample di luma, un intero sample
di luma o 4 sample di luma. Nella modalità AMVP affine è possibile scegliere un quarto di sample
di luma, un intero sample di luma o 1/16 sample di luma. L'indicazione di risoluzione MVD a
livello di CU è segnalata condizionalmente se il CU corrente ha almeno una componente MVD non
zero. Se tutte le componenti MVD (cioè, tutti gli MVD sia orizzontale che verticale per le liste di
riferimento L0 ed L1) sono zero, allora viene assunta la risoluzione MVD ad un quarto di sample di
luma. Per un CU che ha almeno una componente MVD non zero, viene segnalato un primo flag per
indicare se viene utilizzata la precisione MVD ad un quarto di sample di luma per il CU. Se il primo
flag è 0, non c'è bisogno di alcuna altra segnalazione e viene utilizzata la precisione MVD ad un
quarto di sample di luma per il CU corrente, altrimenti, viene segnalato un secondo flag per indicare
se viene utilizzata la precisione a metà sample di luma o altre precisioni (sample intero o 4 sample
di luma) per il CU normal AMVP. Nel caso di metà sample di luma, viene utilizzato un filtro di
interpolazione a 6 tap invece che quello ad 8 tap di default per la posizione del sample, altrimenti,
viene segnalato un terzo flag per indicare se viene utilizzata la precisione MVD ad un sample di
luma intero o 4 sample di luma. Nel caso del CU AMVP affine, il secondo flag viene utilizzato per
indicare se viene utilizzata la precisione MVD a sample di luma intero oppure ad 1/16 di sample di
luma. Per assicurarsi che il MV ricostruito abbia la precisione desiderata (un quarto di sample di
luma, metà sample di luma, sample di luma intero, 4 sample di luma), i predittori di vettori
spostamento per il CU sono arrotondati alla stessa precisione di quella dell'MVD prima di essere
aggiunti insieme con l'MVD. I predittori di vettore spostamento sono arrotondati verso zero (cioè,
un predittore di vettore spostamento negativo è arrotondato verso +∞ e quello positivo verso -∞).
L'encoder determina la risoluzione di vettore spostamento per il CU corrente usando un controllo di
ridondanza. Per evitare di dover effettuare sempre il controllo di ridondanza a livello di CU 4 volte
per ogni risoluzione MVD, negli encoder attuali dell'H.266 il controllo di ridondanza di precisione
MVD che non siano quella da un quarto di sample di luma viene invocato in maniera condizionale.
Per la modalità AVMP normale, il costo del controllo di ridondanza della precisione MVD ad un
quarto di sample di luma viene prima computato e poi comparato a quello della precisione a sample
di luma intero per vedere se è necessario controllare ulteriormente il costo del controllo di
ridondanza e compararlo in questo caso con la precisione MVD a 4 sample di luma. Quando il costo
del controllo di ridondanza per la precisione MVD ad un quarto di sample di luma è molto più
piccolo di quello di sample di luma intero, allora il calcolo del costo per quello da 4 sample di luma
viene skippato. Allo stesso modo, il controllo per la precisione a metà sample di luma è skippato se
il costo del controllo di ridondanza del sample di luma intero è molto più grande di quello del
miglior costo della precisione appena testata. Per la modalità AMVP affine, se non viene selezionata
la modalità inter affine dopo aver controllato il costo di rate-distortion della modalità merge/skipe
affine, allora la modalità merge/skip, la precisione MVD ad un quarto di sample AMVP normale ed
affine e quella ad 1/16 di sample di luma vengono skippate. Inoltre, i parametri affini ottenuti nella
precisione ad un quarto di sample MV nella modalità inter affine vengono usati come punto di
inizio per le modalità inter affini di precisione MV da 1/16 di sample di luma ed un quarto di
sample di luma.

- Salvataggio del motion field

Nell'H.266, la precisione più alta di un vettore spostamento esplicitamente segnalata è quella di un


quarto di luma di sample. In alcune modalità di predizione inter tipo la modalità affine, i vettori
spostamento sono derivati con precisione da 1/16 di sample di luma e la predizione moto-
compensata è effettuata con precisione 1/16 di sample. In termini di salvataggio del motion field
interno, tutti i vettori spostamento sono salvati con precisione 1/16 di sample di luma. Per il
salvataggio del motion field temporale usato dal TMVP ed ATVMP, la compressione del motion
field è effettuata a granularità 8x8 in contrasto all'H.265 in cui avveniva a granularità 16x16.

- Bi-Predizione con peso a livello di CU

Nell'H.265, il segnale di bi-predizione è generato facendo la media di due segnali di predizione


ottenuti da due immagini di riferimento diverse ed usando due vettori spostamento diversi.
Nell'H.266, la modalità di bi-predizione è estesa oltre alla semplice media per consentire una media
pesata dei due segnali di predizione:

Pbi-pred = [(8-w) * P0 + w * P1 + 4] > 3

Sono consentiti 5 pesi nella bi-predizione con media pesata: w ∈{-2, 3, 4, 5, 10}. Per ogni CU bi-
predetto, il peso w (weight) è determinato in uno dei due modi:

1) per i CU non merge, l'index di peso viene segnalato dopo la differenza dei vettori spostamento
2) per un CU merge, l'index di peso è assunto dai blocchi vicini (confinanti) sulla base dell'index
dei candidati di merge.

La bi-predizione con peso a livello di CU viene detta BCW e viene applicata solo ai CU con 256
sample di luma o superiori (cioè la larghezza del CU per l'altezza del CU deve essere maggiore o
uguale a 256). Per immagini a basso delay, vengono usati tutti e 5 i pesi, mentre per quelle non a
basso delay, solamente 3 pesi vengono usati, in particolare: w ∈ {3, 4, 5}.
Lato encoder, vengono applicati degli algoritmi di ricerca veloci per trovare l'index di peso senza
aumentare significativamente la complessità dell'encoder. Quando vengono combinati con AMVR,
vengono controllati in maniera condizionale i pesi disuguali per le precisioni di vettore spostamento
ad 1-pel e 4-pel se l'immagine corrente è a basso delay. Quando vengono combinati con la modalità
affine, verrà effettuato il controllo solo se la modalità affine è stata scelta come modalità migliore.
Quando due immagini di riferimento in una bi-predizione sono le stesse, il controllo è effettuato in
maniera condizionale. Infine, il controllo non viene effettuato quando ci sono alcune condizioni, a
seconda della distanza POC tra l'immagine attuale e le sue immagini di riferimento, il QP ed il
livello temporale. L'indice di peso BCW è codificato usando un bin context coded seguito da un bin
bypass coded. Il primo bin indica se vengono usati pesi uguali e, se vengono usati pesi disuguali,
vengono segnalati bin aggiuntivi usando il bypass coding per indicare quale peso disuguale è
utilizzato. La predizione pesata (detta WP – Weighted Prediction), in realtà, è uno strumento di
codifica supportato già dall'H.264 e dall'H.265 per encodare efficientemente i video che hanno delle
dissolvenze e quindi anche l'H.266 lo supporta. La predizione pesata consente dei parametri di pesi
(peso ed offset) e questi vengono segnalati per ogni immagine di riferimento in ognuna della liste
L0 ed L1, dopodiché, durante la moto-compensazione, i pesi e gli offset delle immagini di
riferimento corrispondenti vengono applicati. Ora, il nuovo BCW e la vecchia WP di cui ho appena
parlato sono entrambi inclusi nell'H.266 ma siccome sono fatti per tipologie di contenuti video
molto diverse, per evitare interazioni tra i due, se un CU utilizza la WP, allora non viene segnalato
l'index di peso BCW e w è assunto essere 4 (cioè vengono utilizzati pesi uguali). Per un CU merge,
l'indice di peso è assunto dai blocchi vicini (confinanti) a seconda dell'indice del candidato di
merge. Questo può essere applicato sia alla modalità di merge normale sia e quella affine ereditata.
Per la modalità di merge affine costruita, le informazioni di spostamento affine vengono costruite
sulla base dell'informazione di spostamento fino a 3 blocchi. L'indice BCW per un CU che usa la
modalità di merge affine costruita è semplicemente posto uguale all'indice BCW del primo punto di
controllo MV. Nell'H.266, CIIP e BCW non possono essere applicati insieme per un CU. Quando un
CU è codificato con la modalità CIIP, allora l'indice BCW del CU corrente è posto uguale a 2, cioè
pesi uguali.

- Optical Flow bi-direzionale

L'Optical Flow bi-direzionale, detto BDOF, è usato per raffinare il segnale di bi-predizione di un
CU a livello di sotto-blocchi da 4x4 ed è applicato se un CU soddisfa le seguenti condizioni:

1) Il CU è codificato usando la modalità di bi-predizione "vera", nel senso che una delle due
immagini di riferimento è prima dell'immagine attuale nell'ordine di riproduzione e l'altra è dopo di
essa.

2) Le distanza (cioè la differenza POC) dalle due immagini di riferimento all'immagine attuale è la
stessa.

3) Entrambe le immagini di riferimento sono short-term.

4) Il CU non è codificato usando la modalità affine o la modalità di merge ATMVP.

5) Il CU ha più di 64 sample di luma.

6) Sia l'altezza che la larghezza del CU sono maggiori o uguali ad 8 sample di luma.

7) L'indice di peso BCW indica pesi uguali.


8) WP non è abilitata per il CU corrente.

9) La modalità CIIP non è utilizzata per il CU corrente.

Il BDOF è solamente applicato alle componenti di luma. Il concetto alla base del BDOF è l'optical
flow, che presuppone che lo spostamento di un oggetto sia regolare. Per ogni sotto-blocco da 4x4
viene calcolato un raffinamento di spostamento vx, vy minimizzando la differenza dei sample di
predizione L0 ed L1. Il raffinamento di spostamento è poi utilizzato per aggiustare i valori di
sample bi-predetto nel sotto-blocco da 4x4. Nel processo di BDOF vengono applicati i seguenti
step: prima vengono computati i gradienti orizzontale e verticale dei due segnali di predizione
calcolando direttamente la differenza tra i due sample vicini (confinanti):

dove: I (k ) ( i , j ) sono i valori dei sample alle coordinate i, j del segnale di predizione nella lista k,
k=0,1, e lo shift1 è calcolato sulla base del bit depth del luma, bitDepth, come:

shift1 = massimo(6, bitDepth-6)

Dopodiché l'auto e cross-correlazione dei gradienti S1, S2, S3, S5 ed S6 sono calcolate come:

in cui:

dove Ω è una finestra da 6x6 intorno al sotto-blocco da 4x4 ed i valori di nc ed nb sono posti uguale
a:

minimo(1, bitDepth – 11) e minimo(4, bitDepth -8)

Il raffinamento dello spostamento vx, vy è poi diviso usando i termini di cross ed auto correlazione.
Sulla base del raffinamento di spostamento e dei gradienti, vengono calcolati i seguenti
aggiustamenti per ogni sample nel sotto-blocco da 4x4:
Infine, vengono calcolati i sample BDOF del CU aggiustando i sample di bi-predizione:

Questi valori sono selezionati in modo che i moltiplicatori nel processo di BDOF non eccedano i
15bit ed il massimo numero di bit dei parametri intermedi sia tenuto sotto ai 32bit. Per poter
derivare i valori di gradiente, devono essere generati alcuni sample di predizione I (k ) ( i , j ) nella lista
k (k = 0,1) fuori dai confini del CU corrente.

Regione del CU estesa usata nel BDOF

Il BDOF dell'H.266 utilizza una riga/colonna estesa intorno ai confini del CU, come mostrato qua
sopra. Per poter controllare la complessità computazionale della generazione di sample di
predizione fuori dai confini, i sample di predizione nell'area estesa (posizioni bianche) vengono
generati prendendo i sample di riferimento alle posizioni intere vicine (usando l'operazione floor()
sulle coordinate) direttamente e senza interpolazione e viene usato il filtro di interpolazione di
moto-compensazione normale ad 8 tap per generare i sample di predizione all'interno del CU
(posizioni grigie). Questi valori di sample estesi sono usati solamente nel calcolo del gradiente e,
per i rimanenti step del processo di BDOF, se sono necessari valori di sample e gradiente al di fuori
dei confini del CU, viene fatto il padding (cioè vengono ripetuti) dal loro vicino più prossimo.
Quando la larghezza o l'altezza del CU (o entrambe) sono maggiori di 16 sample di luma, questo
verrà diviso in sotto-blocchi con larghezza e altezza pari a 16 sample di luma ed i confini di sotto-
blocco sono trattati come confini CU nel processo di BDOF; la massima grandezza è quindi limitata
a 16x16 ed inoltre, per ogni sotto-blocco, è possibile skippare il processo di BDOF. Il threshold è
posto uguale a:

[8 * L * (A >> 1)]

dove L indica la larghezza del sotto-blocco ed A indica l'altezza del sotto-blocco.


Per evitare una ulteriore complessità nel calcolo SAD, viene ri-utilizzato l'SAD tra i sample di
predizione L0 ed L1 iniziale calcolato nel processo di DVMR. Se il BCW è abilitato per il blocco
corrente (cioè l'indice di peso BCW indica pesi disuguali), allora l'optical flow bi-direzionale è
disabilitato. In maniera analoga, se la WP è abilitata per il blocco corrente (cioè il flag
luma_weight_lx è 1 per una delle due immagini di riferimento), allora il BDOF è disabilitato.
Infine, il BDOF è disabilitato anche quando un CU è codificato con la modalità MVD simmetrica o
la modalità CIIP.

- Raffinamento del vettore spostamento lato decoder

Per aumentare l'accuratezza dei MV della modalità di merge, lato decoder, nell'H.266, viene
applicato un raffinamento del vettore spostamento basato sul match bilaterale. Nell'operazione di bi-
predizione, viene ricercato un MV raffinato intorno ai MV iniziali nella lista di immagini di
riferimento L0 e nella lista di immagini di riferimento L1. Il metodo BM calcola la distorsione tra i
due blocchi candidati nella lista di immagine di riferimento L0 e nella lista L1.

Raffinamento dei vettori spostamento lato decoder

Come mostrato nell'immagine qua sopra, viene calcolato l'SAD tra i blocchi rossi basati su ogni
candidato MV attorno al MV iniziale. Il candidato MV con l'SAD più basso diventa il MV raffinato
e viene usato per generare il segnale bi-predetto. Nell'H.266, il DMVR può essere applicato ai CU
codificati con le seguenti modalità e caratteristiche:

1) Modalità di merge a livello di CU con MV di bi-predizione

2) Un'immagine di riferimento è nel passato ed un'altra immagine di riferimento è nel futuro rispetto
all'immagine corrente.

3) La distanza (differenza POC) tra due immagini di riferimento e l'immagine corrente è la stessa.
4) Entrambe le immagini di riferimento sono short-term.

5) L'altezza e la larghezza dei CU sono maggiori o uguali ad 8 sample di luma.

6) L'indice di peso BCW indica pesi uguali.

7) WP non è abilitata per il blocco corrente.

8) La modalità CIIP non è utilizzata per il blocco corrente.

Il MV raffinato derivato dal processo DMVR è utilizzato per generare i sample di predizione inter
ed è anche usato nella predizione di vettore spostamento temporale per la codifica di immagini
future, mentre il MV originale è utilizzato nel processo di de-blocking ed anche nella predizione di
vettore spostamento spaziale per la codifica di CU futuri.

- Schema di ricerca del DVMR

Nel DVMR, i punti di ricerca sono circondati dal MV iniziale e l'offset MV segue la regola di
"difference mirroring" MV. Detto altrimenti, qualsiasi punto controllato dal DMVR, denotato dalla
coppia candidata MV (MV0, MV1) segue queste due equazioni:

MV0' = MV0 + MVoffset e MV1' = MV1 – MVoffset

dove MVoffset rappresenta l'offset di raffinamento tra il MV iniziale ed il MV raffinato in una delle
immagini di riferimento. Il range di raffinamento di ricerca è 2 sample interi di luma dal MV
iniziale. La ricerca include la fase di ricerca dell'offset del sample intero e quella di raffinamento del
sample frazionario. Per la ricerca dell'offset di sample intero viene applicata la ricerca intera a 25
punti. Il SAD della coppia MV iniziale viene calcolato e, se è inferiore di un certo threshold, la
prima fase è terminata, altrimenti, i SAD dei rimanenti 24 punti vengono calcolati e controllati in
ordine di scansione di raster. Viene così selezionato come output il punto con il SAD più piccolo.
Per ridurre lo svantaggio dell'incertezza del raffinamento DMVR, viene preferito il MV originale e
il SAD tra i blocchi di riferimento riferiti dai candidati MV iniziali vengono ridotti di 1/4 del valore
del SAD. La ricerca di sample interi è seguita dal raffinamento dei sample frazionari. Per riddure la
complessità computazionale, il raffinamento dei sample frazionari è derivato usando una equazione
di superficie di errore parametrica invece di una ricerca aggiuntiva con la comparazione SAD. Il
raffinamento di sample frazionari è invocato in maniera condizionale a seconda dell'output della
fase di ricerca di sample interi. Quando questa ricerca (quella di sample interi) è terminata con il
centro che ha il SAD più piccolo nella prima o nella seconda iterazione, viene poi applicato il
raffinamento di sample frazionario. Nella stima dell'offset di sotto-pixel basata sulla superficie di
errore parametrica, il costo della posizione centrale e quello alle 4 posizioni vicine (confinanti) dal
centro vengono usati in un'equazione di superficie di errore parabolica 2D:

dove (xmin,ymin) corrispondono alla posizione frazionaria con il costo minore e C corrisponde al
valore di costo minimo. Risolvendo le equazioni di sopra usando il valore di costo dei 5 punti di
ricerca, xmin è computato come:

Xmin = [E(-1,0) – E(1,0)] / [2(E(-1,0) + E(1,0) – 2E(0,0)]


lo stesso vale per ymin che sarebbe [E(0,-1) – E(0,1)] / lo stesso ed il valore di xmin e ymin è
automaticamente limitato tra -8 ed 8 slice. Tutti i valori di costo sono positivi ed il valore più
piccolo è E(0,0). Questo corrisponde a metà offset pel con accuratezza 1/16 pel MV. I frazionari
computati xmin,ymin sono poi aggiunti al raffinamento di distanza intero MV per ottenere il
raffinamento accurato sotto-pixel delta MV.

- Interpolazione bilineare e padding dei sample

Nell'H.266, la risoluzione dei MV è 1/16 sample di luma. I sample alla posizione frazionaria sono
interpolati usando un filtro di interpolazione ad 8 tap. Nel DMVR, i punti di ricerca circondano il
MV pel frazionario iniziale con offset di sample intero, dunque i sample di questa posizione
frazionaria devono essere interpolati durante il processo di ricerca DMVR. Per ridurre la
complessità di calcolo, viene utilizzato un filtro di interpolazione bilineare per generare i sample
frazionari per il processo di ricerca in DMVR. Un altro effetto importante è che usando un filtro
bilineare con un range di ricerca a 2 sample, il DVMR non accede a più sample di rfierimento
rispetto al normale processo di moto-compensazione. Dopo che il MV raffinato viene ottenuto con
il processo di ricerca DMVR, viene applicato un normale filtro di interpolazione ad 8 tap per
generare la predizione finale. Per non accedere a più sample di riferimento rispetto al normale
processo di moto-compensazione, i sample che non sono necessari per il processo di interpolazione
basato sui MV originali ma che sono necessari per il processo di interpolazione basato sui MV
raffinati, vengono sottoposti a padding.

- Massima grandezza del DMVR

Quando la larghezza e l'altezza (o entrambi) di un CU sono maggiori di 16 sample di luma, questo


verrà diviso in sotto-blocchi con larghezza e altezza pari a 16 sample di luma. La massima
grandezza per il processo di ricerca DMVR è quindi 16x16.

- Modalità di Partizionamento Geometrico

Nell'H.266, la modalità di partizionamento geometrico è supportata nella predizione inter e viene


segnalata usando un flag a livello CU come un tipo di modalità merge, con altre modalità merge che
includono la modalità merge normale, la modalità MMVD, la modalità CIIP e la modalità di merge
dei sotto-blocchi. La modalità di partizionamento geometrico supporta un totale di 64 partizioni per
ogni grandezza di CU possibile w × h=2m × 2n con m, n ∈{3, ..., 6} esclusi 8x64 e 64x8. Quando
viene utilizzata questa modalità, un CU è partizionato in due parti da una linea retta collocata
geometricamente.

Esempio di partizionamento GPM raggruppato per angoli identici

Il posizionamento della linea retta è derivato matematicamente dai parametri di angolo ed offset di
una partizione specifica. Ogni parte di una partizione geometrica nel CU è predetta inter usando il
suo stesso spostamento; per ogni partizione, è consentita solamente la predizione unitaria (mono-
predizione) per assicurarsi che – così come per la bi-predizione convenzionale – siano necessarie
solamente 2 predizioni moto-compensate per ogni CU.
Se viene utilizzata la modalità di partizionamento geometrico per il CU corrente, allora vengono
segnalati anche un indice di partizione geometrica che indica la modalità di partizione (angolo ed
offset) e due indici di merge (uno per ogni partizione). La grandezza massima dei candidati GPM è
segnalata esplicitamente nell'SPS e specifica la sintassi di binarizzazione per gli indici GPM di
merge. Dopo aver predetto ognuna delle parti della partizione geometrica, i valori di sample sui
confini di partizione geometrica sono aggiustati usando un processo di blending con peso adattivo.
Questo è il segnale di predizione per l'intero CU ed i processi di trasformata e quantizzazione
verranno applicati all'intero CU come in altre modalità di predizione ed infine, viene salvato il
motion field di un CU predetto usando la modalità di partizionamento geometrico.

- Costruzione della lista del candidato di predizione unitaria (mono-predizione)

La lista dei candidati di predizione unitaria (mono-predizione) è derivata direttamente dalla lista di
candidati di merge costruita secondo il processo di predizione di merge esteso. Sia n l'index di
spostamento di predizione unitaria (mono-predizione) nella lista di candidati di predizione unitaria
geometrica. LX è il vettore spostamento del candidato di merge esteso n-esimo, con X uguale alla
parità di n, ed è usato come vettore spostamento di predizione unitaria n-esimo per la modalità di
partizionamento geometrico.

Selezione del MV di predizione unitaria per la modalità di partizionamento geometrico

Nell'immagine di sopra, i vettori spostamento sono segnati con "x". Nel caso non esista un vettore
spostamento LX corrispondente dell'ennesimo candidato di merge esteso, viene usato il vettore
spostamento L(1 – X) dello stesso candidato.

- Blending sui confini di partizionamento geometrico

Dopo aver predetto ogni parte di una partizione geometrica usando lo spostamento, viene applicato
il blending ai due segnali di predizione per derivare i sample intorno ai confini di partizionamento
geometrico. Il peso di blending per ogni posizione del CU è derivato sulla base della distanza tra la
posizione individuale ed il confine della partizione. La distanza dalla posizione (x, y) al confine di
partizione è derivata come:
dove i, j sono gli indici dell'angolo e dell'offset di una partizione geometrica, che dipendono
dall'indice di partizione geometrica segnalato. Il segno di ρx,j e ρy,j dipende dall'indice di angolo i.
I pesi per ogni parte della partizione geometrica sono derivati come:

dove partIdx dipende dall'indice di angolo i.


Un esempio di peso w0 è dato da:

Esempio di peso w0 usando la modalità di partizionamento geometrico


- Salvataggio del motion field per la modalità di partizionamento geometrico

Vengono presi Mv1 dalla prima parte della partizione geometrica ed Mv2 dalla seconda parte della
partizione geometrica e vengono combinati e salvati nel motion field di un CU codificato con la
modalità di partizionamento geometrico. Il tipo di vettore spostamento salvato per ogni posizione
individuale nel motion field è determinato da:

sType| (motionIdx) | < 32 ? 2 : ( motionIdx <= 0 ? (1 – partIdx) : partIdx )

dove motionIdx è uguale a d(4x + 2, 4y + 2), mentre partIdx dipende dall'indice di angolo i. Se
sType è uguale a 0 o 1, allora Mv0 od Mv1 vengono salvati nel motion field corrispondente,
altrimenti, se sType è uguale a 2, viene salvato un Mv combinato formato da Mv0 ed Mv2. Se Mv1
ed Mv2 appartengono a liste di immagini di riferimento differenti (uno viene da L0 ed uno da L1),
allora Mv1 ed Mv2 vengono combinati semplicemente per formare i vettori spostamento di bi-
predizione, altrimenti, se Mv1 ed Mv2 vengono dalla stessa lista, viene salvato solamente Mv2 di
predizione unidirezionale di spostamento.

- Predizione inter ed intra combinata (CIIP – Combined Inter Intra Prediction)

Nell'H.266, quando un CU è codificato in modalità merge, se questo contiene almeno 64 sample di


luma (cioè se la larghezza del CU per l'altezza del CU è pari o superiore a 64) e se sia la larghezza
che l'altezza del CU sono minori di 128 sample di luma, viene segnalato un flag aggiuntivo per
indicare se la predizione combinata inter/intra (CIIP Mode – Combined Inter Intra Prediction Mode)
è applicata al CU corrente. Questo tipo di predizione combina un segnale di predizione inter con un
segnale di predizione intra. Il segnale di predizione inter nella modalità CIIP Pinter è derivato usando
lo stesso processo di predizione inter applicato alla modalità di merge normale ed il segnale di
predizione intra Pintra è derivato seguendo il processo di predizione intra normale con la modalità
planar. I segnali di predizione inter ed intra vengono dunque combinati usando la media pesata,
dove il valore del peso è calcolato a seconda delle modalità di codifica dei blocchi confinanti
superiore e sinistro. Se è disponibile il confinante superiore ed è codificato intra, allora isIntraTop
viene posto ad 1, altrimenti viene posto a 0. Se è disponibile il confinante sinistro ed è codificato
intra, allora isIntraLeft è posto ad 1, altrimenti viene posto a 0. Se (isIntraLeft + isIntraTop) è
uguale a 2, allora wt è posto a 3, altrimenti, se è uguale ad 1, wt è posto a 2, altrimenti wt è 1.

Blocchi superiore e sinistro usati nella derivazione CIIP


La predizione CIIP è data da:

PCIIP = [ ( 4 – wt ) * Pinter + wt * Pintra + 2] > 2

- Trasformate di blocchi di grandi dimensioni con azzeramenti ad alta frequenza

Nell'H.266, è possibile effettuare le trasformate su blocchi di grandi dimensioni, fino a 64x64, il che
è utile per lo più per i video in 8K. I coefficienti di trasformata ad alta frequenza sono azzerati per i
blocchi di trasformata di grandezza (larghezza o altezza od entrambe) uguali a 64x64 in modo che
solo i coefficienti a bassa frequenza siano mantenuti. Ad esempio, per un blocco di trasformata da
MxN, con M come larghezza di blocco ed N come altezza di blocco, quando M è guaule a 64,
solamente le 32 colonne di coefficienti di trasformata a sinistra sono mantenute. In maniera analoga,
quando N è uguale a 64, solamente le 32 righe di coefficienti di trasformata in alto sono mantenute.
Quando viene usata la modalità di trasformata "skip" per un blocco grande, viene usato l'intero
blocco senza azzerare alcun valore ed in più non c'è lo shift di trasformata. Negli encoder, è inoltre
possibile settare la massima grandezza di trasformata nell'SPS in modo che si abbia la flessibilità di
scegliere grandezze di trasformata fino a 32 o 64 a seconda dell'implementazione desiderata.

- Selezione di trasformata

In aggiunta alla DCT-II che è stata utilizzata nell'H.265, nell'H.266 abbiamo un modulo di MTS che
sta per "Multiple Transform Selection" che viene utilizzato per la codifica residua di blocchi sia
inter che intra. Quello che viene fatto è utilizzare diverse trasformate e le nuove matrici di
trasformata introdotte sono la DST-VII e la DCT-VIII.

Funzioni di base per le trasformate DCT-II e VIII e per la DST-VII per un input ad N punti

Per poter mantenere l'ortogonalità della matrice di trasformata, le matrici di trasformata sono
quantizzate in maniera più accurata rispetto a quelle dell'H.265. Per mantenere i valori intermedi dei
coefficienti di trasformata all'interno del range a 16bit, dopo le trasformate orizzontale e verticale,
tutti i coefficienti devono avere 10bit. Per controllare lo schema MTS, vengono specificati dei flag
di abilitazione separati a livello SPS per intra ed inter. Quando la MTS è abilitata a livello SPS,
viene segnalato un flag a livello di CU per indicare se la MTS è applicata o meno. In questo caso, la
MTS è applicata solamente per il luma. La segnalazione MTS è skippata quando vengono
incontrate una delle seguenti condizioni: la posizione dell'ultimo coefficiente significativo per il TB
di luma è inferiore ad 1 (cioè solo DC), oppure se è situato all'interno della regione azzerata della
MTS. Se il flag CU MTS è uguale a 0, allora la DCT-II è applicata in entrambe le direzioni, tuttavia,
se il flag CU MTS è uguale ad 1, allora vengono segnalati altri due flag per indicare il tipo di
trasformata per le direzioni orizzontale e verticale. La tabella di trasformata e segnalazione è
mostrata di seguito:

MTS_CU_flag MTS_Hor_flag MTS_Ver_flag Intra/inter

Orizzontale Verticale

0 DCT2

0 0 DST7 DST7

0 1 DCT8 DST7

1 1 0 DST7 DCT8

1 1 DCT8 DCT8
Tabella di trasformata e segnalazione

La selezione di trasformata unificata per l'ISP e la MTS implicita è utilizzata per rimuovere le
dipendenze dalla modalità intra e le forme dei blocchi. Se il blocco corrente è in modalità ISP o se è
intra e sia la MTS intra che inter esplicita è abilitata, allora viene utilizzata la DST-VII sia per la
trasformata orizzontale che verticale. Per quanto riguarda la precisione della matrice di trasformata,
vengono utilizzati core di trasformata ad 8bit, dunque, tutti i core di trasformata usati nell'H.265
sono lasciati intatti, inclusa la DCT-II a 4 punti, la DST-VII ad 8 punti e la DCT-II a 16 e 32 punti.
Inoltre, altri core di trasformata come la DCT-II a 64 punti, la DCT-VIII a 4 punti, la DST-VII e
DCT-VIII ad 8, 16 e 32 punti usano core di trasformata ad 8bit. Per ridurre la complessità di DST-
VII e DCT-VIII, vengono azzerati i coefficienti di trasformata ad alta frequenza per i blocchi di
grandezza (larghezza o altezza o entrambi) pari a 32 e solamente i coefficienti all'interno della
regione a bassa frequenza da 16x16 vengono mantenuti. Così come nell'H.265, i residui di un
blocco possono essere codificati con la modalità di trasformata "skip". Per evitare la ridondanza
della codifica di sintassi, il flag "skip" non è segnalato quando MTS_CU_flag non è uguale a 0. La
trasformata implicita MTS è posta su DCT-II quando sono attivi LFNST o MIP per il CU corrente;
inoltre, la MTS implicita può ancora essere abilitata quando è abilitata la modalità MTS per i
blocchi inter.

- Trasformate non separabili a bassa frequenza

Le trasformate non separabili a bassa frequenza sono dette LFNST e, nell'H.266, sono applicate ttra
la trasformata primaria in avanti e la quantizzazione (lato encoder) e tra la de-quantizzazione e la
trasformata primaria inversa (lato decoder).
Processo di LFNST (Trasformata non separabile a bassa frequenza)

Nel processo di LFNST, viene applicata una trasformata non separabile da 4x4 od 8x8 a seconda
della grandezza del blocco; ad esempio, quella da 4x4 viene applicata per blocchi piccoli (cioè
min(larghezza, altezza) < 8) e quella da 8x8 viene applicata per blocchi più grandi (cioè
min(larghezza, altezza) > 4). L'applicazione di una trasformata non separabile che viene usata nel
processo di LFNST è descritta con un esempio; si supponga di dover applicare una 4x4 e si abbia il
blocco di input X dato da:

sia ⃑
X il vettore che lo rappresenta, allora:
La trasformata non separabile è calcolata come ⃑ F =T ∙ ⃑X , dove ⃑
F indica il vettore di coefficienti di
trasformata e T è una matrice di trasformata da 16x16. Il vettore di coefficienti 16x1 ⃑ F è poi ri-
organizzato successivamente come blocco da 4x4 usando l'ordine di scansione per quel blocco
(orizzontale, verticale o diagonale). I coefficienti con indice più piccolo saranno inseriti con l'index
di scansione più piccolo nel blocco di coefficienti da 4x4.

- Trasformate non separabili ridotte

Il processo di LFNST è basato sull'approccio a moltiplicazione di matrice diretta per applicare la


trasformata non separabile in modo che sia implementata in un solo passo senza avere molteplici
iterazioni, tuttavia, le dimensioni della matrice di trasformata non separabile devono essere ridotte
per minimizzare la complessità computazionale e lo spazio in memoria richiesto per salvare i
coefficienti di trasformata. Da qua, nascono le trasformate non separabili ridotte ed il metodo RST
che viene usato nel processo LFNST. L'idea principale è quella di mappare un vettore di dimensione
N (dove N è generalmente uguale a 64 per NSST da 8x8) ad un vettore R-dimensionale in uno
spazio differente, in cui N/R (R < N) è il fattore di riduzione. Dunque, invece di avere una matrice
NxN, la matrice RST diventa una matrice RxN:

dove le R righe della trasformata sono R basi dello spazio N dimensionale. La matrice di
trasformata inversa per RT è la trasposta della sua trasformata in avanti. Per un processo LFNST
8x8, viene applicato un fattore di riduzione di 4 e la matrice diretta da 64x64, che è una matrice di
trasformta non separabile convenzionale da 8x8, è ridotta ad una matrice diretta da 16x48. Dunque,
la matrice inversa RST da 48x16 viene usata lato decoder per generare i coefficiente di trasformata
primaria nelle regioni da 8x8 superiori sinistre. Quando le matrici da 16x48 vengono applicate
invece di quelle da 16x64 con la stessa configurazione di trasformata, ognuna di esse prende 48 dati
in input da 3 blocchi da 4x4 nel blocco superiore sinistro da 8x8 escludendo il blocco da 4x4
inferiore destro. Con l'aiuto delle dimensioni ridotte, l'utilizzo della memoria per salvare tutte le
matrici LFNST è ridotto da 10 KB ad 8 KB con un calo di performance ragionevole. Per ridurre la
complessità del processo LFNST, questo è ristretto ad essere applicabile solo nel caso in cui tutti i
coefficienti fuori dal primo sotto-gruppo di coefficienti sono non significativi. Dunque, tutti i
coefficienti di trasformata primaria devono essere 0 quando è applicato il processo LFNST. Questo
permette un condizionamento della segnalazione dell'index LFNST sull'ultima posizione
significativa e quindi evita una ulteriore scansione di coefficienti nel design LFNST corrente. Il
caso peggiore da gestire per il processo LFNST (in termini di moltiplicazioni per pixel) restringe le
trasformate non separabili di blocchi da 4x4 ed 8x8 a trasformate da 8x16 ed 8x48. In questi casi,
l'ultima posizione di scansione significativa deve essere inferiore ad 8 quando è applicato il
processo LFNST, per altre grandezze < 16. Per blocchi con forma da 4xN ed Nx4 ed N > 8, la
restrizione proposta implica che il processo LFNST sia applicato una volta sola e solo alla regione
superiore sinistra da 4x4. Visto che quando viene applicato il processo LFNST tutti i coefficienti
primari sono 0, il numero di operazioni necessarie per le trasformate primarie è ridotto.
- Selezione di trasformata LFNST

Ci sono 4 set di trasformate in totale e 2 matrici di trasformate non separabili (kernel) per set di
trasformata nel processo LFNST. Il mapping dalla modalità di predizione intra al set di trasformata
è pre-definito come di seguito:

Modalità di Predizione Intra Index del Set di Trasformata


Modalità di Predizione Intra < 0 1
0 <= Modalità di Predizione Intra <= 1 0
2 <= Modalità di Predizione Intra <= 12 1
13 <= Modalità di Predizione Intra <= 23 2
24 <= Modalità di Predizione Intra <= 44 3
45 <= Modalità di Predizione Intra <= 55 2
56 <= Modalità di Predizione Intra <= 80 1
81 <= Modalità di Predizione Intra <= 83 0
Tabella di Selezione di Trasformata

Se viene usata una delle 3 modalità CCLM (INTRA_LT_CCLM, INTRA_T_CCLM o


INTRA_L_CCLM) per il blocco corrente (81 <= Modalità di Predizione Intra <= 83), viene
selezionato il set di trasformate 0 per il blocco di chroma corrente. Per ogni set di trasformate, il
candidato di trasformata secondario non separabile selezionato viene specificato ulteriormente
dall’index LFNST esplicitamente segnalato e, questo, è segnalato nel bitstream per ogni CU Intra
dopo i coefficienti di trasformata.

- Segnalazione dell'index LFNST ed interazione con altri strumenti

Visto che il processo LFNST è applicabile solo se tutti i coefficienti fuori dal primo sotto-gruppo di
coefficienti sono non significativi, la codifica dell'index LFNST dipende dalla posizione dell'ultimo
coefficiente significativo. Inoltre, l'index LFNST è context codec ma non dipende dalla modalità di
predizione intra e solamente il primo bin è context coded. Non solo, il processo LFNST è applicato
ai CU intra sia negli slice intra che in quelli inter e sia per il luma che per il chroma. Se viene
abilitato il dual tree, gli indici LFNST per luma e chroma vengono segnalati separatamente. Per uno
slice inter (il dual tree è disabilitato), viene segnalato un solo indice LFNST che viene usato sia per
il luma che per il chroma. Considerando che un CU più grande di 64x64 viene partizionato
implicitamente (tiling TU) a causa delle restrizioni di grandezza di trasformata massima già
esistenti (64x64), la ricerca di indice LFNST potrebbe aumentare il buffering dei dati di 4 volte per
certe situazioni di decodifica, dunque, la massima gandezza permessa per il processo LFNST è
ristretta a 64x64 ed il processo può essere abilitato solo per la DCT-II. La segnalazione dell'index
LFNST avviene prima di quella dell'indice MTS.

- Trasformate di Sottoblocchi

Nell'H.266 è stata introdotta la trasformata di sotto-blocchi per un CU predetto inter. In questa


modalità di trasformata, solamente una sotto-partizione del blocco residuo viene codificata per il
CU.
Quando un CU predetto inter con cu_cbf è uguale ad 1, il flag cu_sbt potrebbe essere segnalato per
indicare se l'intero blocco residuo o una sotto-partizione del blocco residuo è codificata. Nel caso
dell'intero blocco residuo, l'informazione MTS inter è parsata ulteriormente per determinare il tipo
di trasformata del CU. Nel caso della sotto-partizione, una parte del blocco residuo viene codificata
con la trasformata adattiva e l'altra parte viene azzerata. Quando viene utilizzata la trasformata di
sotto-blocco (SBT – Sub-block Transform) per un CU codificato inter, vengono segnalate nel
bitstream le informazioni relative al tipo di SBT ed alla posizione di SBT. Ci sono due tipi di SBT e
due posizioni di SBT.

Posizione SBT, tipo e tipo di trasformata

Per la SBT-V (o SBT-H) la larghezza del TU (o altezza) può essere uguale a metà della larghezza (o
altezza) del CU o 1/4 della larghezza (o altezza) del CU, risultando in un partizionamento 2:2 o in
uno partizionamento1:3/3:1. Il partizionamento 2:2 è come un partizionamento ad albero binario
(BT) mentre il partizionamento 1:3/3:1 è come un partizionamento ad albero binario asimmetrico
(ABT). Nel partizionamento ABT, solamente la regione piccola contiene i residui non zero. Se una
dimensione del CU è 8 in termini di sample di luma, allora il partizionamento 1:3/3:1 su quella
dimensione è disabilitato e ci sono al massimo 8 modalità SBT per un CU. La selezione della
trasformata dipendente dalla posizione è applicata sui blocchi di trasformata di luma in SBT-V ed
SBT-H (il TB del chroma usa sempre la DCT-II). Le due posizioni di SBT-H ed SBT-V sono
associate con diverse trasformate. Ad esempio, le trasformate orizzontali e verticali per SBT-V di
posizione 0 sono rispettivamente la DCT-VIII e la DST-VII. Quando un lato del TU residuo è
maggiore di 32, la trasformata per entrambe le dimensioni è la DCT-II. Dunque, la trasformata di
sotto-blocchi specifica il tiling TU, il cbf e il tipo di trasformata orizzontale e verticale di un blocco
residuo. Per quanto rigurda i CU codificati con la modalità inter-intra combinata, non abbiamo SBT.
- Parametro di controllo della quantizzazione

Nell'H.266, il QP massimo è stato esteso da 51 a 63 e la segnalazione del QP iniziale è stata


cambiata di conseguenza. Il valore iniziale di SliceQpY è stato modificato al layer di slice segment
in cui è codificato un valore di slice_qp_delta non zero. In particolare, il valore init_qp_minus26 è
stato modificato per stare tra -26+QpBdOffsetY e +37. Quando la dimensione di un blocco di
trasformata non è una potenza di 4, i coefficienti di trasformata sono processati assieme ad una
modifica del QP o QP-LevelScale piuttosto che usare una moltiplicazione per 181/256 (o 181/128)
per compensare per uno scaling implicito da parte del processo di trasformata. Per il blocco di
trasformata "skip", il QP (Quantization Parameter) minimo consentito è definito come 4 perché la
grandezza del passo di quantizzazione diventa 1 quando QP è uguale a 4. Nell'H.265 (ed anche
nell'H.264) viene utilizzato un look-up table fisso per convertire il parametro di quantizzazione di
luma QPY in un parametro di quantizzazione del chroma QPC. Nell'H.266, viene invece usato un
mapping del QP da luma a chroma più flessibile: invece di avere un look-up table fisso, la relazione
di mapping QP da luma a chroma è segnalata nell'SPS usando un modello lineare modulare
flessibile con l'unico limite che il coefficiente angolare di ogni modulo non può essere negativo
(cioè, quando il QP del luma aumenta, anche il QP del chroma deve aumentare oppure rimanere
uguale, ma non può diminuire). Il modello lineare modulare è definito da:

1) Il numero di moduli nel modello


2) I delta QP di input (luma) ed output (chroma) per quel modulo

Il range di input del modello lineare modulare è [-QpBdOffsetY, 63] e l'output è [-QpBdOffsetC, 63].
La relazione di mapping del QP può essere segnalata separatamente per Cb, Cr oppure segnalata
assieme per tutti e 3 i tipi di codifica residua. Così come nell'H.265, è stato implementato
l'adattamento del QP a livello di CU ed i valori Delta QP per le componenti di luma e chroma
possono essere segnalati separatamente. Per le componenti di chroma, i valori di offset QP del
chroma consentiti sono segnalati nella forma di lista di offset nel PPS in maniera simile all'H.265.
Vengono definite delle liste in maniera separata per Cb, Cr e per la codifica unita Cb/Cr e sono
consentiti fino a 6 valori di offset per ogni lista. A livello di CU, viene segnalato un index per
indicare quale dei valori di offset nella lista di offset viene usato per aggiustare il QP del chroma per
quel CU. La segnalazione dell'offset QP del CU del chroma è consistente anche con la disponibilità
del CU QP VPDU e, per CU maggiori di 64x64, viene inviato l'offset QP del chroma con la prima
unità di trasformata a prescindere che abbia CBF non zero o meno.

- Quantizzazione Scalare Dipendente

La quantizzazione scalare dell'H.265 viene usata anche nell'H.266, ma con un nuovo concetto
chiamato "Quantizzazione Scalare Dipendente". La Quantizzazione Scalare Dipendente si riferisce
ad un approccio in cui l'insieme di valori di ricostruzione ammissibili per un coefficiente di
trasformata dipende dai valori dei livelli di coefficiente di trasformata che precedono il livello del
coefficiente di trasformata nell'ordine di ricostruzione. L'effetto principale di questo approccio è
che, rispetto alla quantizzazione scalare indipendente convenzionale usata nell'H.265, i vettori di
ricostruzione ammissibili sono impacchettati in maniera più densa nello spazio vettoriale N-
dimensionale, dove "N" rappresenta il numero di coefficienti di trasformata in un blocco di
trasformata. Questo significa che, per un numero medio di vettori di ricostruzione ammissibili per
un volume di unità N-dimensionale, diminuisce la distorsione media tra un vettore di input e la sua
ricostruzione più vicina. L'approccio della quantizzazione scalare dipendente consiste nel definire
due quantizzatori scalari con diversi livelli di ricostruzione ed un processo per switchare tra i due
quantizzatori scalari.
Rappresentazione dei due quantizzatori scalari usati nella quantizzazione dipendente

La figura di sopra mostra due quantizzatori scalari: Q0 e Q1. La posizione dei livelli di
ricostruzione disponibili è specificata in maniera univoca da un passo di quantizzazione di
grandezza Δ. Il quantizzatore scalare utilizzato (Q0 o Q1) non è segnalato esplicitamente nel
bitstream, ma viene determinato dalle parity dei livelli del coefficiente di trasformata che precede il
coefficiente di trasformata corrente nell'ordine di codifica/ricostruzione.

Transizione di stato e selezione del quantizzatore per la quantizzazione dipendente

Come illustrato nell'immagine qua sopra, lo switch tra i due quantizzatori scalari (Q0 e Q1) è
realizzato utilizzato una macchina a stati con 4 stati. Lo stato può assumere 4 diversi valori: 0, 1, 2,
3 ed è determinato in maniera univoca dalle parity dei livelli del coefficiente di trasformata che
precede il coefficiente di trasformata corrente nell'ordine di codifica/ricostruzione. All'inizio della
quantizzazione inversa per un blocco di trasformata, lo stato viene settato uguale a 0. I coefficienti
di trasformata sono ricostruiti nell'ordine di scansione (cioè nello stesso ordine in cui sono
decodificati entropicamente). Dopo che il coefficiente di trasformata corrente è stato ricostruito, lo
stato viene aggiornato come mostrato qua sopra (k denota il valore del livello del coefficiente di
trasformata).

- Matrici di Scaling

L'H.266 supporta l'uso delle matrici di scaling di default ma anche l'utilizzo di matrici di scaling
definite dall'utente. Nella modalità di default le matrici di scaling sono tutte flat, con elementi
uguali a 16 per tutte le grandezze di TB. Le modalità di codifica IBC ed Intra condividono le stesse
matrici di scaling. Per quanto riguarda le matrici definite dall'utente, il valore di MatrixType e
MatrixType_DC viene aggiornato come:

MatrixType = 30
= 2 * 3 *5
= (intra e IBC/inter) * (componenti Y/Cb/Cr) *
* (grandezza TB da 4x4 a 64x64 per il luma e da 4x4 a 32x32 per il chroma)

MatrixType_DC = 14
=2*3+4*2
= (intra e IBC/inter per Y) * (grandezza TB da 16x16, 32x32, 64x64) +
+ (intra ed IBC/inter * Componenti Cb/Cr) * (grandezza TB da 16x16, 32x32)

I valori DC sono codificati separatamente per le matrici di scaling 16x16, 32x32 e 64x64. Per i TB
di grandezza inferiore ad 8x8, vengono segnalati tutti gli elementi in una matrice di scaling. Se i TB
hanno dimensione maggiore o uguale ad 8x8, vengono segnalati solamente 64 elementi in una
matrice di scaling da 8x8 come matrice di scaling di base. Per ottenere le matrici quadrate di
grandezza superiore ad 8x8, viene fatto upsampling della matrice di scaling di base da 8x8 (tramite
duplicazione degli elementi) fino alla grandezza corrispondente (cioè 16x16, 32x32, 64x64).
Quando viene applicato l'azzeramento dei coefficienti ad alta frequenza per la trasformata a 64
punti, le alte frequenze corrispondenti delle matrici di scaling vengono anch'esse azzerate. Dunque,
se la larghezza o l'altezza del TB sono maggiori o uguali a 32, solamente i coefficienti della metà
sinistra o superiore vengono mantenuti ed i coefficienti rimanenti vengono posti a 0. Non solo, il
numero di elementi segnalato per la matrice di scaling da 64x64 è ridotto da 8x8 a 3 sotto-matrici da
4x4, visto che gli elementi inferiori destri da 4x4 non sono mai usati. Nell'H.266, i blocchi di
codifica di chroma intra (CB) da 2x2, 2x4 e 4x2 non esistono e la grandezza del blocco intra più
piccola che si può avere è pari a 2x8 ed 8x2 così come la grandezza più piccola del blocco di
chroma IBC. Non solo, la predizione inter è disabilitata per i CB di luma da 4x4, dunque, i blocchi
di chroma da 2x2 possono essere creati solamente applicato una trasformata di sotto-blocchi (SBT).

- Codifica unificata dei residui di chroma

Un altro strumento utilizzato dall'H.266 è la codifica unificata dei residui di chroma detta JCCR.
L'attivazione della modalità JCCR è indicata con un flag a livello di TU:
tu_joint_cbcr_residual_flag e la modalità selezionata è indicata in maniera implicita dai CBF del
chroma. Il flag è presente se uno o entrambi i CBF del chroma per un TU sono pari a 1. Nel PPS e
slice header, i valori dell'offset QP del chroma sono segnalati per differenziare i valori segnalati
nella modalità JCCR dai valori segnalati per la modalità classica. Questi valori di offset QP del
chroma sono utilizzati per derivare i valori QP del chroma per alcuni blocchi codificati usando la
modalità JCCR. Nella modalità JCCR abbiamo 3 sotto-modalità; quando è attiva una sotto-modalità
JCCR (tipo la sotto-modalità 2) in un TU, l'offset QP del chroma è aggiunto al QP del chroma
derivato dal luma applicato durante la quantizzazione e la decodifica di quel TU. Per altre sotto-
modalità JCCR (tipo la sotto-modalità 1 e la 3), i QP del chroma sono derivati nella stessa modalità
dei blocchi Cb e Cr convenzionali. Il processo di ricostruzione dei residui di chroma (resCb e resCr)
dai blocchi di trasformata trasmessi è:
tu_cbf_cb tu_cbf_cr Ricostruzione dei residui Cb e Cr modalità
resCb[x][y] = resJointC[x][y] 1
1 0
resCr[x][y] = ( CSign * resJointC[x][y] ) >> 1
resCb[x][y] = resJointC[x][y] 2
1 1
resCr[x][y] = CSign * resJointC[x][y]
resCb[x][y] = ( CSign * resJointC[x][y] ) >> 1 3
0 1
resCr[x][y] = resJointC[x][y]
Ricostruzione dei residui di chroma; il valore Csign è un valore si segno (+1 o -1), che è specificato
nello slice header, mentre resJointC[][] è il residuo trasmesso

Quando la modalità JCCR è attiva, viene segnalato un solo blocco residuo di chroma unificato
(resJointC[x][y]) ed il blocco residuo per Cb (resCb) e quello per Cr (resCr) sono derivati
considerando le informazioni come tu_cbf_cb, tu_cbf_cr e Csign, che è un valore di segno
specificato nello slice header. Lato encoder, le componenti di chroma unificate sono derivate e, a
seconda della modalità, resJointC{1,2} sono generati in maniera diversa. Se la modalità è pari a 2
(residuo singolo con ricostruzione Cb = C, Cr = CSign * C), il residuo unificato è dato da:

resJointC[x][y] + CSign * resCr[x][y]) / 2

altrimenti, se la modalità è pari a 1 (residuo singolo con ricostruzione Cb = C, Cr = [CSign * C] /2),


il residuo unificato è dato da:

resJointC[x][y] = (4 * resCb[x][y] + 2 * CSign * resCr[x][y]) / 5

altrimenti, se la modalità è pari a 3 (residuo singolo con ricostruzione Cr = C, Cb = [CSign * C] /2),


il residuo unificato è dato da:

resJointC[x][y] = (4 * resCr[x][y] + 2 * CSign * resCb[x][y]) /5

Le 3 sotto-modalità di codifica del chroma unificata appena descritte sono supportate solo negli
slice I, mentre negli slice P e B solamente la modalità 2 è supportata. Dunque, negli slice P e B,
l'elemento di sintassi tu_joint_cbcr_residual_flag è presente solamente se entrambi i cbfs del
chroma sono 1. La modalità JCCR può essere combinata con la modalità di trasformata skip del
chroma (TS). Per velocizzare la decisione che deve prendere l'encoder, la selezione di trasformata
JCCR dipende se la codifica indipendente delle componenti Cb e Cr seleziona la DCT-II o la TS
come trasformata migliore ed anche dal fatto che ci siano o meno coefficienti non zero nella
codifica del chroma indipendente. In particolare, se una componente di chroma sceglie la DCT-II (o
la TS) e l'altra componente è tutta zero, oppure se entrambe le componenti di chroma scelgono la
DCT-II (o la TS), allora verrà considerata solo la DCT-II (o solo la TS) nell'encoding JCCR.
Altrimenti, se una componente sceglie la DCT-II e l'altra sceglie la TS, allora verranno considerate
entrambe durante l'encoding JCCR.

- Codifica entropica

Nell'H.266 il CABAC contiene 3 cambiamenti fondamentali rispetto all'H.265:

1) L'engine alla base del CABAC è diverso


2) La struttura codifica dei residui separata per i blocchi di trasformata e di skip

3) Context Modelling per i coefficienti di trasformata

Dunque è bene soffermarsi su ciascuno di questi; partiamo dal primo.

Engine alla base del CABAC

L'engine alla base del CABAC nell'H.265 usa un processo di transizione tra 64 stati di probabilità
rappresentativi basato su una tabella. Nell'H.265 il range ivlCurrRange che rappresenta lo stato
dell'engine di codifica è quantizzato ad un insieme di 4 valori prima di calcolare il nuovo intervallo.
La transizione di stato, nell'H.265, può essere implementata usando una tabella contenente tutti i
valori pre-computati 64x4 8bit per approssimare i valori di ivlCurrRange * pLPS(pStateIdx), dove
pLPS è la probabilità del simbolo meno probabile (LPS) e pStateIdx è l'index dello stato corrente.
Inoltre, una decisione di decodifica può essere implementata usando una LUT pre-computata. Prima
viene ottenuto con una LUT ivlLpsRange, poi questo viene usato per aggiornare ivlCurrRange e
calcolare l'output binVal:

ivlLpsRange = rangeTabLps[pStateIdx][qRangeIdx]

nell'H.266, la probabilità è espressa linearmente dall'index di probabilità pStateIdx, dunque, tutti i


calcoli possono essere fatti con equazioni senza usare una LUT. Per migliorare l'accuratezza della
stima di probabilità, viene applicato un modello di aggiornamento della probabilità multi-ipotesi. Il
pStateIdx usato nella sotto-divisione dell'intervallo nel codificatore aritmetico binario è una
combinazione di due probabilità pStateIdx0 e pStateIdx1. Le due probabilità sono associate con
ogni context model e sono aggiornate indipendentemente con diversi adaption rate. Gli adaption
rate di pStateIdx0 e pStateIdx1 per ogni context model sono pre-allenati sulla base delle statistiche
dei bin associati. La stima di probabilità pStateIdx è la media delle stime delle due ipotesi.
L'immagine di sopra mostra una tabella di flusso per la decodifica di una singola decisione binaria
in H.266. Così come avveniva nell'H.265, anche nell'H.266 il CABAC ha un processo di
inizializzazione dipendente dal QP invocato all'inizio di ogni slice. Dato il valore iniziale del QP di
luma per lo slice, lo stato di probabilità iniziale del context model, denotato come preCtxState, è:

m = slopeIdx * 5 – 45
n = (offsetIdx << 3) + 7
preCtxState = Clip3{1, 127, [(m * (QP – 32) >> 4] + n}

dove slopeIdx ed offsetIdx sono ristretti a 3 bit ed i valori di inizializzazione totali sono
rappresentati con precisione a 6bit. Lo stato di probabilità preCtxState rappresenta direttamente la
probabilità nel dominio lineare. Dunque, preCtxState ha solo bisogno di operazioni di shifting
prima di essere dato in pasto all'engine di codifica aritmetica e viene salvato anche il mapping del
dominio da logaritmico a lineare così come la tabella a 256 byte.

pStateIdx0 = preCtxState << 3


pStateIdx1 = preCtxState << 7

La struttura codifica dei residui separata per i blocchi di trasformata e di skip

Nell'H.265, i coefficienti di trasformata di un blocco di codifica sono codificati usando un gruppo di


coefficienti non sovrapposto (CG o sotto-blocchi) ed ogni CG contiene i coefficienti di un blocco
4x4 di un blocco di codifica. Nell'H.266, la selezione della grandezza del gruppo dei coefficienti
diventa dipendente solo dalla grandezza del TB rimuovendo così la dipendenza dal tipo di canale; di
conseguenza, è possibile avere diversi CG (1x16, 2x8, 8x2, 2x4, 4x2 e 16x1). I CG all'interno di un
blocco di codifica ed i coefficienti di trasformata all'interno di un CG sono codificati secondo un
ordini di scansione predefiniti. Per restringere il massimo numero di bin context coded per pixel,
vengono usati l'area del TB e le componenti di colore. Per un TB di luma, il numero massimo di bin
context coded è pari a TB_zosize * 1.75, mentre per un TB di chroma è TB_zosize * 1.25, dove
"TB_zosize" indica il numero di sample all'interno di un TB dopo che i coefficienti sono azzerati. A
differenza dell'H.265 in cui la codifica dei residui è fatta per le statistiche e caratteristiche dei livelli
dei coefficienti di trasformata, nell'H.266 vengono usate due strutture di codifica dei residui
separate per i coefficienti di trasformata e per i coefficienti di trasformata skip. Nella codifica dei
coefficienti di trasformata, una variabile, remBinsPass1, viene posta pari al massimo numero di bin
context coded e poi viene diminuita di 1 quando viene segnalato un bin context coded. Finché la
remBinsPass1 è maggiore o uguale a 4, il primo passo di codifica, che include i flag sig_coeff_flag,
abs_level_gt1_flag, par_level_flag ed abs_level_gt3_flag, è codificato usando i bin context coded.
Se il numero di bin context coded non è maggiore di Mccb nel primo passo di codifica, allora il
resto delle informazioni di livello, che vengono indicate per essere codificate ulteriormente nel
primo passo, vengono codificate con elementi di sintassi abs_remainder usando il codice Golomb-
rice e i bin bypass coded. Quando remBinsPass1 diventa minore di 4, i coefficienti che non sono
stati codificati nel primo passo vengono codificati direttamente nel secondo passo con l'elemento di
sintassi dec_abs_level. Il remBinsPass1 è resettato per ogni TB e questo avviene non più di una
volta per TB. Per un sotto-blocco di coefficienti, se remBinsPass1 è minore di 4, l'intero sotto-
blocco di coefficienti è codificato usando bin bypass coded. Dopo tutta la codifica di livello
menzionata sopra, i segni (sign_flag) per tutte le posizioni di scansione con sig_coeff_flag è posto
uguale ad 1 ed è finalmente bypass coded. Per i passi 2 e 3 viene utilizzata la derivazione del
parametro rice (ricePar) unificata; l'unica differenza è che baseLevel è posto a 4 per il passo 2 ed a 0
per il passo 3. Il parametro rice è determinato non solo sulla base della somma dei livelli assoluti
dei 5 coefficienti di trasformata vicini (confinanti) nel template locale, ma anche dal livello base:
RicePara = RiceParTable{max[min(31, sumAbs – 5 * baseLevel), 0]}

Struttura di codifica dei residui per i blocchi di trasformata

Dopo la terminazione del primo passo di codifica del sotto-blocco, il valore assoluto di ognuno dei
coefficienti rimasti da codificare è codificato dall'elemento di sintassi dec_abs_level, che
corrisponde ad un valore di livello assoluto modificato con il valore di livello zero mappato
condizionatamente ad un valore non zero. Lato encoder, il valore dell'elemento di sintassi
dec_abs_level è derivato dal livello assoluto (absLevel), dallo stato di quantizzatore dipendente
(Qstate) e dal valore del parametro rice (RicePara) come:

ZeroPos = (QState < 2 ? 1 : 2) << RicePara


if (absLevel == 0)
{
dec_abs_level = ZeroPos
}
else
{
dec_abs_level = (absLevel <= ZeroPos) ? (absLevel – 1) : absLevel
}

In maniera simile all'H.265, l'H.266 supporta la modalità di trasformata skip che è consentita per i
blocchi di luma e chroma; in questa modalità, le caratteristiche statistiche del segnale sono diverse
da quelle dei coefficienti di trasformata ed applicare una trasformata ai residui per ottenere una
maggiore compressione di energia attorno alle componenti a bassa frequenza è generalmente meno
efficace. I residui con queste caratteristiche diverse si trovano generalmente nei contenuti sintetici
rispetto a quelli catturati naturalmente da una camera.

Context Modelling per i coefficienti di trasformata

La selezione dei modelli di probabilità per gli elementi di sintassi legati ai valori assoluti dei livelli
dei coefficienti di trasformata dipende dai valori dei livelli assoluti o dai livelli assoluti
parzialmente ricostruiti nell'intorno locale.
Template usato per la selezione dei modelli di probabilità: il quadrato nero indica la posizione di
scansione corrente ed i quadrati blu rappresentano l'intorno locale usato

Il modello di probabilità selezionato dipende dalla somma dei livelli assoluti (o livelli assoluti
parzialmente ricostruiti) in un interno locale ed il numero di livelli assoluti maggiori di 0 (dato dal
numero di sg_coeff_flags uguale ad 1) nell'intorno locale. Il context modelling e la binarizzazione
dipendono da 4 misure per l'intorno locale:

1) numSig: il numero di livelli non zero nell'intorno locale

2) sumAbs1: la somma di livelli assoluti parzialmente ricostruiti (absLevel1) dopo il primo passo
nell'intorno locale

3) sumAbs: la somma dei livelli assoluti ricostruiti nell'intorno locale

4) la posizione diagonale d: la somma delle coordinate orizzontali e verticali della posizione di


scansione corrente all'interno del blocco di trasformata

Sulla base dei valori di numSig, sumAbs1 e d, i modelli di probabilità vengono selezionati per la
codifica sig_flag, par_flag, gt1_flag e gt2_flag. Il parametro rice per la binarizzazione
abs_remainder viene selezionato sulla base dei valori di sumAbs e numSig. Nell'H.266, per ridurre
il costo computazionale della DST-VII e DCT-VIII a 32 punti viene usato un MTS a 32 punti ridotto
(RMTS32) basato sullo skip dei coefficienti ad alta frequenza e, inoltre, vengono considerati tutti i
tipi di azzeramento (cioè, RMTS32 e l'azzeramento esistente per le componenti ad alta frequenza in
DCT-II). In particolare, la binarizzazione della codifica dell'ultima posizione di coefficiente non
zero è codificata sulla base della dimensione di TU ridotta e la selezione di context model per la
codifica della posizione dell'ultimo coefficiente non zero è determinata dalla dimensione di TU
originale.
Inoltre, vengono usati 60 context model per encodare il sig_coeff_flag dei coefficienti di
trasformata. La selezione dell'index di context model è basata sulla somma di un massimo di 5
livelli assoluti parzialmente ricostruiti precedenti, cioè locSumAbsPass1:

se cIdx è pari a 0, allora ctxInc è:

ctxInc= 12 * Max(0, QState – 1) + Min[(locSumAbsPass1 + 1) >> 1, 3] + [d < 2 ? 8 : (d < 5 ? 4: 0)]

altrimenti, se cIdx è maggiore di 0, ctxInc è:

ctxInc= 36 + 8 * Max(0, QState – 1) + Min[(locSumAbsPass1 + 1) >> 1,3] + (d < 2 ? 4 : 0)

- Filtri in-loop (in generale)

Ci sono un totale di 3 filtri in-loop nell'H.266. Oltre al filtro di deblocking ed al SAO (i due filtri
dell'H.265), c'è un nuovo filtro di loop adattivo chiamato ALF che viene applicato. L'ALF
comprende l'ALF del luma, l'ALF del chroma e l'ALF di cross-componente detto CC-ALF. Il
processo di filtering ALF è fatto in modo che l'ALF di luma, quello di chroma e quello di cross-
component possano essere in parallelo. L'ordine del processo di filtering nell'H.266 è: deblocking,
SAO ed ALF. Per quanto riguarda il SAO, questo è lo stesso dell'H.265. Nell'H.266 è stato inoltre
aggiunto un nuovo processo: il mapping del luma con lo scaling del chroma, chiamato anche
LMCS. Questo nuovo processo, il LMCS, modifica i valori di sample prima dell'encoding e dopo la
ricostruzione ridistribuendo le codeword su tutto il range dinamico e viene eseguito prima del
deblocking.

- Forma del filtro di loop adattivo

Come già detto sopra, nell'H.266 viene applicato un filtro di loop adattivo chiamato ALF: per la
componente di luma, viene scelto uno dei 25 filtri per ogni blocco da 4x4, sulla base della direzione
ed attività dei gradienti locali e vengono utilizzate due forme a diamente. La forma a diamante 7x7
è applicata alle componenti di luma, mentre per le componenti di chroma abbiamo sempre una
forma a diamante ma da 5x5.

Forme del filtro di loop adattivo: diamante da 5x5 per il chroma e diamante da 7x7 per il luma
- Classificazione dei blocchi

Per le componenti di luma, ogni blocco da 4x4 è categorizzato in una delle 25 classi. L'indice di
classificazione C è derivato sulla base della direzionalità D e di un valore quantizzato di attività ^
A:

C=5 D+ ^
A

Per calcolare D ed ^
A , vengono prima calcolati i gradienti orizzontale, verticale e delle due direzioni
diagonali usando un Laplaciano monodimensionale:

dove gli indici i e j si riferiscono alle coordinate del sample superiore sinistro all'interno del blocco
da 4x4 e R(i,j) indica il sample ricostruito alle coordinate i,j. Per ridurre la complessità della
classificazione del blocco, viene applicato il calcolo del Laplaciano monodimensionale sotto-
campionato e vengono usate le stesse posizioni sotto-campionate per il calcolo del gradiente in tutte
le direzioni:

V V V V H H H H

V V V V H H H H

V V V V H H H H

V V V V H H H H

V V V V H H H H

V V V V H H H H

V V V V H H H H

V V V V H H H H

(a) posizioni sotto-campionate per il (b) posizioni sotto-campionate per il


gradiente verticale gradiente orizzontale
D1 D1 D1 D1 D2 D2 D2 D2

D1 D1 D1 D1 D2 D2 D2 D2

D1 D1 D1 D1 D2 D2 D2 D2

D1 D1 D1 D1 D2 D2 D2 D2

D1 D1 D1 D1 D2 D2 D2 D2

D1 D1 D1 D1 D2 D2 D2 D2

D1 D1 D1 D1 D2 D2 D2 D2

D1 D1 D1 D1 D2 D2 D2 D2

(c) posizioni sotto-campionate per il (d) posizioni sotto-campionate per il


gradiente diagonale gradiente diagonale
Calcolo del Laplaciano sotto-campionato
Dunque, i valori D massimo e minimo delle direzioni dei gradienti orizzontale e verticale sono:

max min
gh , v =max ( g h , gv ), gh , v =min ( gh , g v )
ed i valori massimo e minimo del gradiente delle due direzioni diagonali sono:

max min
gd 0 ,d 1 =max ( gd 0 , gd 1 ), gd 0 ,d 1 =min ( g d 0 , g d 1 )
Per derivare il valore di direzionalità D, questi valori vengono comparati tra di loro e con i due
threshold t1 e t2:

Step 1: se entrambi gmax min max min


h , v ≤ t 1 ∙ g h ,v e gd 0 ,d 1 ≤t 1 ∙ gd 0 ,d 1 sono veri, D è posto a 0

Step 2: se gmax min max min


h , v /g h ,v > gd 0 ,d 1 / g d 0 ,d 1, si passa allo Step 3, altrimenti si passa allo Step 4.

max min
Step 3: se gh , v > t 2 ∙ g h ,v , D è posto a 2, altrimenti viene posto ad 1.

Step 4: se gmax min


d 0 ,d 1 >t 2 ∙ gd 0 ,d 1 , D è posto a 4, altrimenti viene posto a 3.

Il valore di attività A è:

A è poi quantizzato ulteriorimente nel range che va da 0 a 4, inclusi, ed il valore quantizzato è ^


A,
mentre per le componenti di chroma non viene applicato alcun metodo di classificazione.

- Trasformazioni geometriche dei coefficienti del filtro e valori di clipping

Prima di filtrare ciascun blocco di luma da 4x4, vengono applicate delle trasformazioni geometriche
come la rotazione ed il flip diagonale o verticale ai coefficienti del filtro f(k,l) ed ai valori di
clipping del filtro corrispondenti c(k,l) a seconda dei valori di gradiente calcolati per quel blocco e,
questo, equivale ad applicare queste trasformazioni ai sample nella regione di supporto del filtro.
Vengono quindi introdotte 3 trasformazioni geometriche: fD (Diagonale), fV (flip verticale), fR
(rotazione):

fD(k,l) = f(l,k), cD(k,l) = c(l,k)


fV(k,l) = f(k, K – l – 1), cV(k,l) = c(k, K – l – 1)
fR(k,l) = f(K – l – 1, k), cR(k,l) = c(K – l – 1, k)

dove K è la dimensione del filtro e 0 <= k, l <= K – 1 sono le coordinate dei coefficienti in modo
che la posizione 0,0 sia nell'angolo superiore sinistro e la posizione K – 1, K – 1 sia in quello
inferiore destro. Le trasformazioni sono applicate ai coefficienti del filtro f(k,l) ed ai valori di
clipping c(k,l) a seconda dei valori del gradiente calcolati per quel blocco. La relazione tra le
trasformazioni ed i 4 gradienti delle 4 direzioni è espressa dalla seguente tabella:
Valori del gradiente Trasformazioni
gd2 < gd1 e gh < gv Nessuna trasformazione
gd2 < gd1 e gv < gh Diagonale
gd1 < gd2 e gh < gv Flip Verticale
gd1 < gd2 e gv < gh Rotazione

- Processo di filtraggio

Lato decoder, quando ALF è abilitato per un CTB, ogni sample R(i,j) all'interno del CU viene
filtrato, risultando così nei valori di sample R'(i,j) come mostrato di seguito:

dove f(k,l) denota i coefficienti decodificati del filtro, K(x,y) è la funzione di clipping e c(k,l)
−L L
denota i parametri decodificati di clipping. Le variabili k ed l variano tra ed dove L denota la
2 2
lunghezza del filtro. La funzione di clipping K(x,y) = min[y, max(-y,x)] corrisponde alla funzione
Clip3(-y, y, x). L'operazione di clipping introduce una non linearità per rendere ALF più efficiente
riducendo l'impatto dei valori di sample vicini che sono troppo differenti da quelli del sample
corrente.

- Filtro di loop adattivo cross component

Il filtro di loop adattivo cross component, detto CC-ALF, usa i valori dei sample di luma per
raffinare ogni componente di chroma applicando un filtro lineare adattivo al canale del luma ed
usando l'output di questa operazione di filtraggio per raffinare il chroma.

Posizionamento del CC-ALF rispetto agli altri filtri di loop


L'immagine di sopra mostra un diagramma che illustra il processo CC-ALF rispetto ai processi di
SAO, di ALF del luma e di ALF del chroma. Il filtraggio nel CC-ALF è ottenuto applicando un
filtro lineare a forma di diamante al canale del luma.

Filtro a forma di diamante

Viene usato un filtro per ogni canale di chroma e l'operazione è espressa da:

dove (x,y) è la componente di chroma, i è la posizione da raffinare, (xY, yY) è la posizione di chroma
basata su (x,y), Si è l'area di supporto del filtro nella componente luma e ci(x0,y0) rappresenta i
coefficienti del filtro. Nelle implementazioni pratiche degli encoder H.266, i coefficienti del filtro
CC-ALF vengono generalmente computati minimizzando l'errore quadrato medio di ogni canale di
chroma rispetto al contenuto di chroma originale e, per far ciò, viene generalmente utilizzato un
processo di derivazione dei coefficienti simile a quello usato per l'ALF del chroma. In particolare,
viene derivata una matrice di correlazione ed i coefficienti sono computati usando la risoluzione per
decomposizione di Cholesky e fino ad un massimo di 8 filtri CC-ALF possono essere tramessi per
singola immagine. I filtri risultanti vengono poi indicati per ognuno dei due canali di chroma sulla
base del CTU. Il design del CC-ALF usa una forma a diamante 3x4 con 8 taps, vengono trasmessi 7
coefficienti del filtro nell'APS ed ognuno dei coefficienti trasmessi ha un range dinamico di 6 bit ed
è ristretto a potenze di 2 come valori. L'ottavo coefficiente del filtro è derivato dal decoder in modo
che la somma dei coefficienti del filtro sia pari a 0. Un APS potrebbe essere referenziato nello slice
header e la selezione del filtro CC-ALF è controllata a livello di CTU per ogni componente di
chroma. Il padding dei confini virtuali orizzontali utilizza lo stesso pattern di accesso in memoria
dell'ALF del luma.
- Segnalazione dei parametri del filtro

I parametri del filtro ALF sono segnalati in un APS (Adaptation Parameter Set). In un APS possono
essere segnalati fino a 25 gruppi di coefficienti di filtro di luma ed indici di valori di clipping e fino
ad 8 gruppi di coefficienti di filtro di chroma ed indici di valori di clipping. Per ridurre l'overhead
dei bit, è possibile unire i coefficienti del filtro di diversa classificazione per le componenti di luma.
Nello slice header, vengono segnalati gli indici degli APS che vengono usati per lo slice corrente. I
valori di indice dei valori di clipping, che sono decodificati dall'APS, consentono di determinare i
valori di clipping usando una tabella di valori di clipping sia per le componenti di luma che di
chroma. Questi valori di clipping sono dipendenti dal bit-depth interno e sono ottenuti usando la
formula:

con B uguale al bit-depth interno ed N pari a 4 che è il numero di valori di clipping consentito in
H.266. AlfClip è poi arrotondato al valore più vicino. Nello slice header, possono essere segnalati
fino a 7 indici APS per specificare i gruppi di filtro del luma che vengono usati per lo slice corrente.
Il processo di filtraggio può essere controllato ulteriormente a livello di CTB. Viene sempre
segnalato un flag per indicare se viene applicato l'ALF al CTB del luma e, questo CTB del luma,
può scegliere un gruppo tra 16 gruppi di filtro fissati ed i gruppi di filtro dall'APS. Viene segnalato
un indice del gruppo di filtro per un CTB di luma per indicare quale gruppo di filtro viene applicato.
I 16 gruppi di filtro fissati sono predefiniti ed hardcoded sia nell'encoder che nel decoder. Per le
componenti di chroma, viene segnalato un indice APS nello slice header per indicare i gruppi di
filtro di chroma usati per lo slice corrente. A livello di CTB, viene segnalato un indice di filtro per
ogni CTB di chroma se c'è più di un gruppo di filtro di chroma nell'APS. I coefficienti di filtro sono
quantizzati con norma pari a 128. Per restringere la complessità di moltiplicazione, viene applicato
un conforming di bitstream in modo che i valori dei coefficienti della posizione non centrale siano
nell'intervallo che va da −27 a 27−1, inclusi. Il coefficiente di posizione centrale, invece, non viene
segnalato nel bitstream ed è considerato essere pari a 128.

- Processo di filtraggio con confini virtuali per la riduzione del line buffer

Nell'H.266, per ridurre il requisito di line buffer dell'ALF, vengono utilizzati un filtraggio ed una
classificazione di blocchi modificate per i sample vicini ai confini orizzontali del CTU. Per questo
motivo, viene definito un confine virtuale, cioè una linea creata shiftando il confine CTU
orizzontale con "N" sample (N=4 per il luma ed N=2 per il chroma).
La classificazione di blocco modificata è applicata per la componente di luma come mostrato
nell'immagine qua sopra. Per il calcolo del gradiente Laplaciano monodimensionale del blocco da
4x4 sopra al confine virtuale, vengono usati solo i sample sopra al confine virtuale. In maniera
analoga, per il calcolo del gradiente Laplaciano monodimensionale del blocco da 4x4 sotto al
confine virtuale, vengono usati solo i sample sotto al confine virtuale. La quantizzazione del valore
di attività A è scalata di conseguenza tenendo in conto il numero di sample ridotto usati nel calcolo
del gradiente Laplaciano monodimensionale. Per il processo di filtraggio, viene usata un'operazione
di padding simmetrica ai confini virtuali sia per le componenti di luma che per le componenti di
chroma.

Filtraggio ALF modificato per la componente di luma ai confini virtuali

Come mostrato nell'immagine qua sopra, quando il sample che viene filtrato è situato sotto al
confine virtuale, i sample confinanti che sono situati sopra al confine virtuale vengono paddati. Nel
frattempo, i sample corrispondenti agli altri lati vengono anch'essi paddati, in maniera simmetrica.
A differenza del metodo di padding simmetrico usato per i confini orizzontali del CTU, per gli slice,
tile e confini di sotto-immagine viene applicato un processo di padding semplice quando viene
disabilitato il filtro. Il processo di padding semplice è applicato anche ai confini dell'immagine. I
sample paddati vengono usati sia per il processo di classificazione che per quello di filtraggio. Per
compensare il padding estremo quando vengono filtrati i sample appena sopra o sotto il confine
virtuale, la forza del filtro viene ridotta sia per il luma che per il chroma aumentando lo shift destro.
- Filtro di Deblocking

Il filtro di deblocking dell'H.266 è simile a quello dell'H.265. Nell'H.266, il filtro di deblocking è


applicato ai confini del CU, ai confini dei sotto-blocchi di trasformata ed ai confini dei sotto-blocchi
di predizione. Questi ultimi includono i PUB (Prediction Unit Boundary) introdotti dal SbTMVP e
le modalità affini ed i confini dei sotto-blocchi di trasformata includono i TUB (Transform Unit
Boundary) introdotti dalle modalità SBT ed ISP. Così come avviene nell'H.265, l'ordine di
processing del filtro di deblocking è definito prima come filtraggio orizzontale per gli edge verticali
per l'intera immagine, seguito poi dal processo di filtraggio verticale applicato in thread paralleli o
applicato ancora sulla base di CTB per CTB con una piccola latenza di processing. Rispetto
all'H.265, comunque, ci sono dei cambiamenti, infatti la forza del filtro di deblocking dipende dal
livello di luma medio dei sample ricostruiti. Inoltre, la tabella di deblocking tC è stata estesa ai
video con bit depth superiori, abbiamo una griglia da 4x4 per il luma, abbiamo il deblocking per i
confini dei sotto-blocchi e la decisione di deblocking è stata adattata a differenze minori nello
spostamento.

- Forza del filtro di deblocking del luma adattiva

Così come avviene nell'H.265, la forza del filtro di deblocking nell'H.266 è controllata dalle
variabili β e tC che sono derivate dai parametri di quantizzazione medi qPL dei due blocchi di
codifica adiacenti. Nell'H.266, il deblocking adattivo del luma può aggiustare ulteriormente la forza
del filtro di deblocking sulla base del livello medio del luma dei sample ricostruiti. Questo
raffinamento ulteriore viene utilizzato per compensare le funzioni di trasferimento non lineari come
la Electro Optical Transfer Function (EOTF) nel dominio linear light. In questo metodo, il filtro di
deblocking controlla la forza aggiungendo un offset al qPL secondo il livello del luma dei sample
ricostruiti. Il livello di luma ricostruito, LL, è derivato come:

LL = [(p0,0 + p0,3 + q0,0 + q0,3) >> 2] / (1 << bitDepth)

dove i valori di sample pi,k e qi,k con i = 0...3 e k = 0 e 3 sono derivati come:
La veriabile qPL è derivata come:

qPL = [(QpQ + QpP + 1) >> 1] + qpOffset

dove QpQ e QpP denotano i parametri di quantizzazione dei CU che contengono i sample q0,0 e p0,0,
rispettivamente. L'offset qpOffset è dipendente dalla funzione di trasferimento e dal livello del luma
ricostruito LL. La funzione di mapping di qpOffset ed il livello del luma sono segnalati nell'SPS e
devono essere derivati secondo le transfer characteristic dei contenuti visto che le funzioni di
trasferimento variano tra i vari formati video.

- Estensione della tabella di deblocking tC ai bit depth superiori

Nell'H.266, il QP massimo è stato cambiato da 51 a 63 ed è stato fatto per riflettere i cambiamenti


corrispondenti nella tabella di deblocking, che deriva i valori dei parametri di deblocking tC
secondo il QP del blocco. La tabella è stata inoltre adattata a bit depth superiori. Di seguito viene
riportata la tabella tC aggiornata al nuovo range QP ed ai video a 10bit:

tC = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3,4,4,4,4,5,5,5,5,7,7,8,9,10,10,11,13,14,15,17,19,21,24,25,29,33,36,41,45,51,57,64,71,80,89,10
0,112,125,141,157,177,198,222,250,280,314,352,395]

- Griglia di deblocking da 4x4 per il luma

L'H.265 usa un griglia di deblocking da 8x8 sia per il luma che per il chroma. Nell'H.266, è stato
introdotto il deblocking su una griglia da 4x4 per i confini del luma in modo da poter gestire gli
artefatti di blocking dalle forme di trasformata rettangolari. Per avere un deblocking del luma su una
griglia da 4x4 che sia parallelizzabile, il numero di sample su cui viene fatto deblocking è ridotto ad
1 per ogni lato di confini di luma verticali dove un lato ha una larghezza pari a 4 o minore od ad 1
sample su ogni lato dei confini di luma orizzontali dove un lato ha altezza pari a 4 o minore.

- Deblocking più forte per il luma

Quando i sample in uno dei lati del confine appartengono ad un blocco grande viene utilizzato un
filtro bilinear per ottenere un deblocking più forte. Un sample appartiene ad un blocco grande se la
sua larghezza è maggiore o uguale a 32 per l'edge verticale e la sua altezza è maggiore o uguale a 32
per l'edge orizzontale. I sample di confine di blocco pi per i = 0 fino ad Sp – 1 e qi per j = 0 fino a Sq
– 1 sono poi rimpiazzati dall'interpolazione lineare:

dove i termini tcPDi e tcPDj sono un clipping che dipende dalla posizione e gj, fi, Middles,t, Ps e Qs
sono:
Sp, Sq
7, 7
(lato p: 7,
lato q: 7)

7, 3
(lato p: 7
lato q: 3)

3, 7
(lato p: 3
lato q: 7)

Derivazione dei parametri di deblocking più forte per il luma

7, 5
(lato p: 7
lato q: 5)

5, 7
(lato p: 5
lato q: 7)

5, 5
(lato p: 5
lato q: 5)

5, 3
(lato p: 5
lato q: 3)
3, 5
(lato p: 3
lato q: 5)

Come detto sopra, il filtraggio più forte del luma viene utilizzato solo se avvengono 3 condizioni.
La prima condizione, Condizione 1, è che si abbia a che fare con un blocco di grandi dimensioni
(deve essere vero quanto detto sopra). Questa condizione si assicura che i sample lato P e lato Q
appartengono ad un blocco di grandi dimensioni. Quindi, se è vera, deve ritornare TRUE. La
seconda condizione e la terza condizione sono:

Condizione 2 = (d < β) ? TRUE : FALSE

Condizione 3 = StrongFilterCondition = (dpq è minore di (β>>4),


sp+sq è minore di (3*β>>5), e Abs(p0−q0) è minore di (5*tC+1)>>1) ? TRUE : FALSE

dove d, dpq, sp ed sq sono le magnitudini dei calcoli del gradiente per determinare la quantità di
dettagli rispetto al threshold basato su β, un threhsold di codifica del noise dipendente dal QP, per
evitare di rimuovere dettagli durante il filtraggio. In maniera simile all'H.265, viene controllata
anche che la magnitudine del gradiente sui confini sia minore del threhsold basato su tC, un
threhsold di forza di deblocking dipendente dal QP.

- Deblocking più forte per il chroma

Per il deblocking più forte del chroma è stato definito il seguente filtro:

p2′= (3*p3+2*p2+p1+p0+q0+4)>>3
p1′= (2*p3+p2+2*p1+p0+q0+q1+4)>>3
p0′= (p3+p2+p1+2*p0+q0+q1+q2+4)>>3

Il filtro di chroma qua sopra effettua deblocking su una griglia di sample di chroma da 8x8 ed i filtri
di chroma più forti sono usati su entrambi i lati dei confini del blocco. Il filtro di chroma viene
selezionato per entrambi i lati degli edge di chroma maggiori o uguali ad 8 (in unità di sample di
chroma). Sono presenti delle condizioni e, queste, vengono controllate in maniera sequenziale; se
una condizione viene soddisfatta, allora vengono skippate le condizioni rimanenti con priorità più
bassa.

bS
Priorità Condizioni
Y U V

Almeno uno dei blocchi adiacenti è codificato con la modalità


6 2 2 2
intra o con la CIIP
Almeno uno dei blocchi adiacenti ha dei coefficienti di
5 1 1 1
trasformata non zero

Uno dei blocchi adiacenti è codificato con la modalità di


4 predizione IBC e l’altro è codificato con la modalità di 1 1 1
predzione inter

La differenza assoluta tra i vettori spostamento che


3 appartengono ai blocchi adiacenti è maggiore o uguale a metà 1 0 0
sample di luma

Le immagini di riferimento a cui si riferiscono i due blocchi


2 1 0 0
adiacenti sono diverse

1 Nessuna delle precedenti 0 0 0

Il deblocking del chroma viene effettuto quando bS è pari a 2 (o se è uguale ad 1 quando viene
rilevato un blocco di grande larghezza).

- Filtro di deblocking per i confini di sotto-blocco

Il processo di deblocking è applicato ad una griglia da 4x4 per i confini dei CU ed i confini di sotto-
blocchi di trasformata e ad una griglia da 8x8 per i confini dei sotto-blocchi di predizione. I confini
dei sotto-blocchi di predizione comprendono i PUB (Prediction Unit Boundaries) introdotti
dall'SbTMVP e le modalità affini, mentre i confini di sotto-blocchi di trasformata comprendono i
TUB (Transform Unit Boundaries) introddoti dalle modalità SBT ed ISP e le trasformate a causa del
partizionamento implicità dei CU di grande larghezza. Per i sotto-blocchi SBT ed ISP, in maniera
simile alla logica nei TU del filtro di deblocking dell'H.265, nell'H.266 il deblocking viene
applicato ad una griglia da 8x8 tenendo in considerazione la differenza tra vettori spostamento ed
immagini di riferimento dei sotto-blocchi di predizione vicini. I confini dei blocchi di trasformata
(boundaries) possono esere sottoposti a deblocking al massimo con 5 sample da un lato di confine
di trasformata che è anche parte di un blocco di codifica in cui la modalità SbTMVP o affine è
utilizzata per consentire un deblocking parallelizzabile. I confini dei sotto-blocchi di predizione
interna che sono a 4 sample dal confine del blocco di trasformata sono sottoposti a deblocking al
massimo da 1 sample su ogni lato, mentre i confini dei sotto-blocchi di predizione interna che sono
ad 8 sample dal confine del blocco di trasformata sono sottoposti a deblocking al massimo da 2
sample su ogni lato del confine e gli altri confini dei sotto-blocchi di predizione interna sono
sottoposti a deblocking al massimo con 3 sample da ogni lato del confine.

- Mapping del luma con scaling del chroma

Nell'H.266 è stato introdotto uno strumento come nuovo blocco di processing prima dei filtri di
loop che fa il mapping del luma con scaling del chroma chiamato LMCS (Luma Mapping Chroma
Scaling). Il LMCS ha due componenti principali:

1) Il mapping in loop dei componenti di luma basati sui modelli lineari adattivi a pezzi
2) Applicazione dello scaling dei residui di chroma dipendenti dal luma per le componenti di
chroma
Mapping del Luma con l'architettura di scaling del Chroma

Lo schema di sopra mostra l'architettura LMCS dal punto di vista del decoder. I blocchi azzurrini
indicano se viene applicato il processing nel dominio mappato e questi comprendono la
quantizzazione inversa, la trasformata inversa, la predizione luma intra e l'aggiunta della predizione
del luma ai residui di luma. I blocchi non colorati indicano i punti in cui il processing è applicato
nel dominio originale (cioè non mappato) e comprendono i filtri di loop come il deblocking, l'ALF,
il SAO, la predizione moto-compensata, la predizione intra del chroma, l'aggiunta della predizione
del chroma ai residui del chroma ed il salvataggio delle immagini decodificate come immagini di
riferimento. I blocchi in giallino non colorati sono i nuovi blocchi funzionali LMCS e comprendono
il mapping in avanti ed indietro del segnale di luma ed il processo di scaling del chroma dipendente
dal luma. Così come la maggior parte degli altri strumenti dell'H.266, anche LMCS può essere
abilitato o disabilitato a livello di sequenza usando il flag SPS.

- Mapping del Luma con un modello lineare a pezzi

Il mapping in loop della componente di luma aggiusta il range dinamico del segnale di input
redistribuendo le parole chiave sul range dinamico per migliorare l'efficienza di compressione. Il
mapping del luma fa uso della funzione del mapping in avanti detto forward mapping (FwdMap) e
la sua funzione inversa corrispondente InvMap. La funzione FwdMap è segnalata usando un
modello lineare a pezzi con 16 pezzi uguali. La funzione InvMap non ha bisogno di essere segnalata
e viene infatti derivata dalla funzione FwdMap. Il modello del mapping del luma è segnalato nella
struttura di sintassi dell'APS (Adaptation Parameter Set) con aps_params_type pari ad 1
(LMCS_APS). Possono essere usati fino a 4 LMCS APS in una sequenza video, ma solamente 1
può essere usato per un'immagine. Il modello del mapping del luma è segnalato usando un modello
lineare a pezzi; questo modello partiziona il range dinamico del segnale in input in 16 pezzi uguali
e, per ogni pezzo, i suoi parametri di mapping lineare sono espressi usando il numero di parole
chiave assegnate a quel pezzo. Si pensi ad un input a 10bit come esempio. Ognuno dei 16 pezzi avrà
64 parole chiave assegnate ad esso di default. Il numero segnalato di parole chiave viene usato per
calcolare il fattore di scaling ed aggiustare la funzione di mapping di conseguenza per quel pezzo.
A livello di slice, viene segnalato un flag di abilitazione LMCS per indicare se il processo LMCS
viene applicato allo slice corrente. Se l'LMCS è abilitato per lo slice corrente, viene segnalato un
aps_id nell'header dello slice per identificare l'APS che porta i parametri di mapping del luma. Ogni
i-esimo pezzo, i = 0...15, del modello lineare a pezzi FwdMap è definito da i due punti pivot di
ingresso InputPivot[] e dai due punti pivot di output (mappati) MappedPivot[]. L'InputPivot[] ed i
MappedPivot[] per un video a 10bit sono computati come:

OrgCW = 64
for i = 0:16, InputPivot[i] = i * OrgCW
for i = 0:16, MappedPivot[i]
MappedPivot[0] = 0;
for (i = 0; i < 16; i++)
MappedPivot[i + 1] = MappedPivot[i] + SignalledCW[i]

dove SignalledCW[i] è il numero di parole chiave segnalato per il pezzo i-esimo. Per un blocco
codificato inter, il blocco di predizione moto-compensato Ypred è calcolato sulla base dei segnali di
riferimento nel DPB, la funzione FwdMap è applicata per mappare il blocco di predizione del luma
nel dominio originale al dominio mappato, Y'pred = FwdMap(Ypred). Per un blocco codificato intra,
la funzione FwdMap non è applicata perché la predizione intra è fatta nel dominio mappato. Dopo
che il blocco ricostruito Yr è stato calcolato, viene applicata la funzione InvMap per convertire i
valori di luma ricostruito nel dominio mappato ai valori di luma ricostruiti nel dominio originale
Y^ i=InvMap ( Y r ) . La funzione InvMap è applicata sia a blocchi di luma codificati intra che a quelli
codificati inter. Il processo di mapping del luma (mapping in avanti ed inverso) può essere
implementato usando o un look-up table oppure usando una computazione ex tempore. Se viene
usato un look-up table (una LUT), allora FwdMapLUT e InvMapLUT possono essere pre-calcolati
e pre-salvati per l'uso a livello di gruppo di tile ed il mapping in avanti ed inverso possono essere
implementati semplicemente come FwdMap(Ypred) = FwdMapLUT(Ypred) e InvMap(Yr) =
InvMapLUT[Yr] rispettivamente (alternativamente può essere usata la computazione ex tempore).
Si prenda una funzione di mapping in avanti, FwdMap, come esempio. Per capire il pezzo a cui il
sample di luma appartiene, il valore del sample viene shiftato a destra di 6 bit (che corrisponde a 16
pezzi uguali), dopodiché vengono recuperati i parametri del modello lineare per quel pezzo e
vengono applicati sul momento per computare i valori di luma mappati. Sia i l'indice di pezzo, siano
a1 ed a2 InputPivot[i] ed InputPivot[i+1] rispettivamente e siano b1 e b2 rispettivamente
MappedPivot[i] e MappedPivot[i+1], allora la funzione FwdMap è:

FwdMap(Ypred) = [(b2 – b1)/(a2 – a1)] * (Ypred – a1) + b1

La funzione InvMap può essere computata sul momento in maniera simile. Generalmente, i pezzi
nel dominio mappato non sono di grandezza uguale, dunque anche il processo di mapping inverso
più semplice a cui si possa pensare richiederebbe comunque una comparazione per capire a quali
pezzi appartengano i valori di sample corrente e, a causa della comparazione, la complessità del
decoder aumenterebbe. Per questo motivo l'H.266 impone un bitstream constraint sui valori dei
punti pivot di output MappedPivot[i]. Supponiamo di avere un video a 10bit (quindi 0-1023) e che
il range del dominio mappato sia diviso in 32 pezzi uguali. Se MappedPivot[i] non è un multiplo di
32, allora MappedPivot[i + 1] e MappedPivot[i] non possono appartenere allo stesso pezzo tra i 32
pezzi di grandezza uguale, quindi MappedPivot[i + 1] >> (BitDepthY – 5) non deve essere uguale a
MappedPivot[i] >> (BitDepthY – 5). Grazie a questa limitazione (bitstream constaint) la funzione
InvMap può anche essere computata usando un sample bit-shift verso destra di 5 bit (che
corrisponde a 32 pezzi di dimensione uguale) per capire il pezzo a cui appartiene il valore del
sample.
- Scaling dei residui di choma dipendente dal luma

Lo scaling dei residui di chroma è fatto per compensare l'interazione tra il segnale del luma ed i suoi
corrispettivi segnali di chroma. Se lo scaling dei residui di chroma è abilitato o meno è indicato a
livello di slice. Se viene abilitato il mapping del luma, viene segnalato un flag aggiuntivo per
indicare se è stato abilitato lo scaling dei residui di chroma dipendente dal luma. Inoltre, questo tipo
di scaling è sempre disabilitato per tutti quei blocchi di chroma la cui area è minore o uguale a 4. Lo
scaling dei residui di chroma dipende dal valore medio dei sample di luma confinanti ricostruiti
superiore e/o sinistro del VPDU corrente. Se il CU corrente è un inter da 128x128 o da 128x64 o da
64x128, allora il fattore di scaling dei residui del chroma derivato per il CU associato con il primo
VDPU viene usato per tutti i blocchi di trasformata in quel CU. Sia avgYr l'average (cioè la media)
dei sample di luma confinanti ricostruiti, allora per trovare il valore di CscaleInv dobbiamo procedere
in 2 step:

1) Trovare l'index Yidx del modello lineare a pezzi a cui appartiene avgYr sulla base della funzione
InvMap.

2) Possiamo a questo punto trovare CscaleInv = cScaleInv[YIdx], dove cScaleInv[] è una LUT a 16
pezzi basata sul valore di SignalledCW[i] ed un valore di offset segnalato nell'APS per il processo
di scaling dei residui del chroma.

A differenza del mapping del luma, che è fatto sulla base dei sample, CscaleInv è un valore costante
per l'intero blocco di chroma e, con CscaleInv, lo scaling dei residui di chroma è applicato come:

CResScale = CRes * CScale = Cres / CscaleInv


(lato encoder)

CRes = CResScale / CScale = CResScale * CscaleInv


(lato decoder)

- Moto-compensazione per i video in 360

Con l'avvento dell'H.265 HEVC si è visto il crescere e propagarsi dei video in 360° ed ipotizzando
una loro sempre più popolare adozione, l'H.266 VVC non poteva non includere degli strumenti di
codifica adatti a questo tipo di video ed uno di questi è proprio la moto-compensazione che deve
essere in grado di poter effettuare una predizione più intelligente rispetto a quella dei classici video.
Nella moto-compensazione classica, quando un vettore spostamento si riferisce ai sample oltre i
confini dell'immagine di riferimento, viene applicato il padding per derivare i valori dei sample
fuori dai confini copiando i valori più prossimi sui confini dell'immagine corrispondente. Per i
video in 360° questo tipo di padding ripetitivo non va bene perché potrebbe creare degli artefatti
video chiamati "seam artefact" una volta che il video viene ricostruito dal decoder. Siccome i video
in 360° sono catturati in una "sfera" che non ha "confini", i sample di riferimento che sono fuori dai
confini dell'immagine di riferimento nel dominio proiettato possono sempre essere ottenuti dai
sample confinanti nel dominio sferico. Per un formato di proiezione generico, potrebbe essere
difficile derivare i sample confinanti corrispondenti nel dominio sferico perché andrebbero effettuati
calcoli di conversione di coordinate da 2D a 3D e da 3D a 2D oltre all'interpolazione per i sample in
posizioni frazionarie. Il problema è molto più semplice per i confini sinistro e destro del formato di
proiezione ERP perché i vicini sferici fuori dal confine dell'immagine sinistra possono essere
ottenuti dai sample dentro il confine dell'immagine destra e vice versa. Visto l'ampio utilizzo del
formato di proiezione ERP e la relativamente semplice implementazione, il wrap orizzontale sulla
moto-compensazione è stato adottato dalla maggior parte degli encoder H.266.

Moto-compensazione orizzontale wrap-around nell'H.266

Nell'immagine di sopra viene mostrato il processo di moto-compensazione orizzontale wrap-


around. Quando una parte del blocco di riferimento è fuori dal confine sinistro o destro
dell'immagine di riferimento nel dominio proiettato, invece del padding ripetitivo, la parte "fuori dal
confine" viene presa dai confini sferici corrispondenti che sono situati all'interno dell'immagine di
riferimento verso il confine destro (o sinistro) nel dominio proiettato. Il padding ripetitivo viene
utilizzato solamente per i confini di immagine superiore ed inferiore. Come mostrato di sopra, la
moto-compensazione orizzontale wrap-around può essere combinata con il metodo di padding non
normativo. Nell'H.266, questo avviene segnalando un elemento di sintassi ad alto livello per
indicare l'offset wrap-around che dovrebbero essere posti pari alla larghezza dell'immagine ERP
prima del padding e, questa sintassi, viene usata per aggiustare la posizione del wrap-around
orizzontale. Questa sintassi non risente della specifica quantità di padding sui confini sinistri e
destri dell'immagine e quindi supporta naturalmente il padding asimmetrico dell'immagine ERP,
ovvero che i padding sinistro e destro possono essere differenti. La moto-compensazione
orizzontale wrap-around fornisce informazioni più significative per la moto-compensazione quando
i sample di riferimento sono fuori dai confini sinistro e destro dell'immagine di riferimento. Nei
video CTC a 360°, questo strumento migliora le performance di compressione non solo in termini
di performance di rate-distortion, ma anche in termini di artefatti chiamati "seam artefact" che
vengono ridotti, aumentando così la qualità soggettiva del video ricostruito a 360°.

- Filtri di loop disabilitati tra i confini virtuali per i video in 360°

Per i formati di proiezione composti da una pluralità di facce, non importa che tipo di disposizione
di frame packing viene utilizzata, ci saranno comunque delle discontinuità tra 2 o più facce
adiacenti nell'immagine frame packed. Ad esempio, consideriamo una configurazione di frame
packing 3x2 in cui la metà superiore ed inferiore dell'immagine frame packed hanno una
discontinuità nella geometria 3D. Se le operazioni di filtraggio in loop vengono effettuate su questa
discontinuità, gli artefatti detti "seam artifacts" potrebbero diventare visibili nel video ricostruito.
Esempio di frame packing 3x2

Per alleviare i seam artifact delle facce, vengono disabilitate le operazioni di filtraggio in loop sulle
discontinuità nelle immagini frame packed. Questa tecnica migliora la qualità soggettiva dei video a
360° e, nell'H.266, sono stati quindi introdotti dei confini virtuali verticali ed orizzontali sui quali le
operazioni di filtering in loop sono disabilitate e le posizioni di questi confini sono segnalate o
nell'SPS o nell'header dell'immagine. Rispetto ad usare 2 tile, una per ogni gruppo di facce
continuee ed a disabilitare le operazioni di filtering in loop tra tile, questa nuova tecnica è più
flessibile in quanto non richiede che la grandezza della faccia sia un multiplo della grandezza del
CTU. La segnalazione è fatta per essere di carattere generale ed applicabile ad altri video che non
sono a 360°. Il numero massimo di confini virtuali verticali è 3 ed il numero massimo di confini
virtuali orizzontali è 3. La distanza tra 2 confini virtuali è maggiore o uguale alla grandezza del
CTU e la granularità di confine virtuale è di 8 sample di luma. I confini virtuali possono anche
essere usati nel GDR (Gradual Decoding Refresh) o PIR (Progressive Intra Refresh) che è una
tecnica che limita grandi variazioni di bitrate tra frame intra I e frame Inter (P o B) mantenendo lo
stesso periodo di random access. Per questa applicazione, le posizioni dei confini virtuali sono
segnalate nell'header dell'immagine visto che le posizioni vengono cambiate frame by frame.

- IBC – Intra Block Copy

L'IBC (Intra Block Copy) è uno strumento atto a migliorare significativamente l'efficienza di
codifica di materiali sintetici. Siccome la modalità IBC è implementata come modalità di codifica a
livello di blocco, viene effettuato il block matching (BM) lato encoder per cercare il vettore
spostamento ideale per ogni CU. Il vettore spostamento (del blocco) viene utilizzato per indicare la
distanza dal blocco corrente al blocco di riferimento che è già stato ricostruito all'interno
dell'immagine corrente. Il vettore spostamento del blocco di luma di un CU codificato IBC è di
precisione intera (int) e lo stesso vale per il blocco di chroma che è anch'esso un int.
Quando viene combinata con l'AMVR, la modalità IBC può switchare tra la precisione di vettore
spostamento ad 1 pel ed a 4 pel. Un CU codificato IBC è trattato come una terza modalità di
predizione oltre alle modalità di predizione inter ed intra. La modalità IBC è applicabile ai CU con
larghezza ed altezza minore o uguale a 64 sample di luma. Lato encoder, la stima di spostamento
basata sull'hash è fatta dall'IBC e l'encoder effettua il controllo RD per i blocchi con larghezza od
altezza non più grandi di 16 sample di luma. Per la modalità non merge, la ricerca di vettori
spostamento del blocco viene prima effettuata usando la ricerca basata sull'hash. Se la ricerca hash
non restituisce un candidato valido, allora viene svolta la ricerca locale basata sul matching dei
blocchi. Nella ricerca basata sull'hash, il matching hash key (32bit CRC) tra il blocco corrente e
quello di riferimento è estesa a tutte le grandezze di blocco consentite. Il calcolo dell'hash key per
ogni posizione nell'immagine corrente è basato sui sotto-blocchi da 4x4. Per il blocco corrente di
dimensione più grande, l'hash key è determinata a matchare quella del blocco di riferimento quando
tutte le hash key dei sotto-blocchi da 4x4 matchano le hash key nelle posizioni corrispondenti di
riferimento. Se vengono trovate matchare con il blocco corrente le hash key di più blocchi di
riferimento, viene calcolato il costo del vettore spostamento del blocco di ogni riferimento che
matcha e viene selezionato quello che ha costo minimo. Nella ricerca del matching dei blocchi, il
range di ricerca è posto per coprire sia i CTU precedenti che quello corrente. A livello di CU, la
modalità IBC è segnalata con un flag e può essere segnalata come modalità AMVP IBC o come
modalità IBC skip/merge. Nella modalità IBC skip/merge, viene usato un indice di candidato di
merge per indicare quale dei vettori spostamento di blocco nella lista dei blocchi codificati IBC
candidati confinanti viene usato per predire il blocco corrente. La lista di merge consiste in
candidati spaziali, HMVP e di coppia. Nella modalità AMVP IBC, la differenza del vettore
spostamento di blocco è codificata nello stesso modo in cui viene codificata la differenza di vettore
spostamento normale. Il metodo di predizione del vettore spostamento di blocco utilizza due
candidati come predittori, uno dal vicino sinistro ed uno dal vicino superiore (se codificato IBC).
Quando uno dei due vicini non è disponibile, viene utilizzato un vettore spostamento di blocco di
default come predittore e viene segnalato un flag per indicare l'indice di predittore di vettore
spostamento di blocco. L'IBC può essere utilizzato assieme ad altri strumenti di codifica, in
particolare può essere usato assieme al candidato di merge a coppie ed al'HMVP: viene generato un
nuovo candidato di merge IBC a coppie facendo la media di due candidati di merge IBC. Per
l'HMVP, lo spostamento IBC viene inserito nell'history buffer per riferimenti futuri. L'IBC non può
essere utilizzato invece assieme alla modalità affine, al CIIP, all'MMVD ed al GPM. Infine, l'IBC
non è consentito per i blocchi di chroma nel caso sia usata la partizione DUAL_TREE.

- BDPCM – Block differential pulse coded modulation

L'H.266 supporta la BDPCM, ovvero la Block Differential Pulse Coded Modulation per la codifica
dei contenuti sintetici e viene segnalato un flag di abilitazione BDPCM a livello di sequenza
nell'SPS; questo flag viene segnalato solo se è abilitata la modalità di trasformata skip nell'SPS.
Quando il BDPCM è abilitato, viene trasmesso un flag a livello di CU se la dimensione di CU è
minore o uguale a MaxTsSize (grandezza massima del blocco per cui è consentita la modalità di
trasformata skip) in termini di sample di luma e se il CU è codificato intra. Questo flag indica se
viene utilizzata la modalità di codifica intra regolare oppure il BDPCM. Se viene utilizzato
quest'ultimo, viene trasmesso un flag di direzione di predizione BDPCM per indicare se la
predizione è orizzontale o verticale, dopodiché il blocco viene predetto usando il processo di
predizione intra orizzontale o verticale con i sample di riferimento non filtrati. Il residuo è
quantizzato e la differenza tra ogni residuo quantizzato ed il suo predittore (cioè il residuo
precedentemente codificato di posizione confinante orizzontale o verticale) viene codificato. Per un
blocco di grandezza M (larghezza) x N (altezza), sia r i , j , 0≤ i≤ M − 1 ,0 ≤ j ≤ N −1 il residuo di
predizione e sia Q ( r i , j ) , 0≤ i ≤ M − 1 ,0 ≤ j ≤ N −1 la versione quantizzata del residuo r i , j.
~
Il BDPCM è applicato ai valori residui quantizzati, risultando così in un array MxN modificato R
con elementi ~r i , j, dove ~r i , j è predetto dai suoi valori residui quantizzati confinanti. Per la modalità di
predizione BDPCM verticale, per 0 ≤ j ≤ ( N −1 ) , per derivare ~r i , j, viene utilizzato:

Per la modalità di predizione BDPCM orizontale, per 0 ≤ i≤ ( M −1 ), per derivare ~r i , j, abbiamo:

Lato decoder, il processo di sopra viene invertito per computare Q ( r i , j ) , 0≤ i≤ M − 1 ,0 ≤ j ≤ N −1 :

i
Q ( r i , j )=∑ ~r k , j , se viene utilizzato il BDPCM verticale
k=0
j
Q ( r i , j )=∑ ~r i ,k , se viene utilizzato il BDPCM orizzontale
k=0

I residui quantizzati inversi Q ( Q ( r i , j ) ) vengono aggiunti ai valori dei blocchi di predizione intra
−1

per produrre i valori di sample ricostruito. I valori residui quantizzati predetti ~r i , j sono inviati al
decoder usando lo stesso processo di codifica dei residui della codifica dei residui della modalità di
trasformata skip. Per la codifica lossless, se il flag slice_ts_residual_coding_disabled_flag è posto
ad 1, i valori residui quantizzati sono inviati al decoder usando la codifica dei residui normale. In
termini di modalità MPM per la modalità di codifica intra futura, la modalità di predizione
orizzontale o verticale viene salvata per il CU codificato BDPCM se la direzione di predizione
BDPCM è rispettivamente orizzontale o verticale. Per il deblocking, se entrambi i blocchi sui lati di
un confine di blocco sono codificati usando il BDPCM, allora quel particolare confine di blocco
non viene sottoposto a deblocking.

- Codifica dei residui per la modalità di trasformata skip

L'H.266 consente di usare la modalità di trasformata skip per i blocchi di luma di grandezza fino a
MaxTsSize, dove il valore MaxTsSize è segnalato nel PPS e può essere al massimo 32. Quando un
CU è codificato nella modalità di trasformata skip, i sui residui di predizione sono quantizzati e
codificati usando il processo di codifica dei residui di trasformata skip. Questo processo è diverso
dal processo di codifica dei coefficienti di trasformata descritto in precedenza, infatti, nella modalità
di trasformata skip, i residui di un TU sono anche codificati in unità di sotto-blocchi non
sovrapposti di grandezza 4x4. Le differenze tra la codifica dei residui di trasformata skip e la
codifica dei residui di trasformata regolare sono:

1) L'ordine di scansione in avanti è applicato per scansionare i sotto-blocchi all'interno del blocco di
trasformata ed anche le posizioni all'interno di un sottoblocco.

2) Non c'è la segnalazione dell'ultima posizione (x,y).

3) il flag coded_sub_block_flag è codificato per ogni sotto-blocco tranne che per l'ultimo sotto-
blocco quando tutti i flag precedenti sono pari a 0.
4) Il context modelling sig_coeff_flag usa un template ridotto ed il context model di sig_coeff_flag
dipende dai valori confinanti superiore e sinistro.

5) Il context model del flag abs_level_gt1 dipende anch'esso dai valori sinistro e superiore
sig_coeff_flag.

6) par_level_flag utilizza solo un context model.

7) Flag aggiuntivi maggiori di 3, 5, 7, 9 sono segnalati per indicare il livello di coefficienti, un


context per ogni flag.

8) La derivazione del parametro rice usando l'ordine fisso = 1 per la binarizzazione dei valori di
resto.

9) Context Model del sign flag è determinato sulla base dei valori confinanti sinistro e superiore ed
il sign flag è parsato dopo il flag sig_coeff_flag per tenere tutti i bin context coded assieme.

Per ogni sotto-blocco, se il flag coded_subblock_flag è pari ad 1 (cioè se c'è almeno unresiduo
quantizzato non nullo nel sotto-blocco), la codifica dei livelli residui quantizzati è fatta in 3 passi di
scansione:

1° Passo di Scansione:
vengono codificati il flag di significanza (sig_coeff_flag), il flag di segno (coeff_sign_flag), il flag
di livello assoluto maggiore di 1 (abs_level_gtx_flag[0]) ed il flag di parity (par_level_flag). Per
una data posizione di scansione, se il flag sig_coeff_flag è pari ad 1, allora il flag coeff_sign_flag
viene codificato, seguito dal flag abs_level_gtx_flag[0] (che specifica se il livello assoluto sia
maggiore di 1 o meno). Se abs_level_gtx_flag[0] è pari ad 1, allora viene codificato anche il
par_devel_flag per specificare la parity del livello assoluto.

2° Passo di Scansione (Maggiore di x):


per ogni posizione di scansione in cui il livello assoluto è maggiore di 1, fino a 4
abs_level_gtx_flag[i] per i = 1...4 vengono codificati per indicare se il livello assoluto ad una
posizione data è maggiore di 3, 5, 7 o 9, rispettivamente.

3° Passo di Scansione (del Resto):


il resto del livello assoluto abs_remainder è codificato in modalità bypass e viene binarizzato
usando un parametro rice fissato di valore 1.

I bin nei passi di scansione 1 e 2 sono context coded finché non viene esaurito al numero massimo
di bin context coded nel TU. Il numero massimo di bin context coded in un blocco residuo è
limitato ad 1.75 * larghezza del blocco * altezza del blocco. I bin nell'ultimo passo di scansione
sono bypass coded. Viene prima posta una variabile, RemCcbs, pari al numero massimo di bin
context coded per il blocco e poi questa viene diminuita di 1 ogni volta che viene codificato un bin
context coded. Finché RemCcbs è maggiore o uguale a 4, gli elementi di sintassi del primo passo di
codifica, che include i flag sig_coeff_flag, coeff_sign_flag, abs_level_gt1_flag e par_level_flag,
sono codificati usando i bin context coded. Se RemCcbs diventa minore di 4 durante il primo passo,
i coefficienti rimanenti che devono ancora essere codificati nel primo passo vengono codificati nel
3° passo. Una volta completato il primo passo, se RemCcbs è maggiore o uguale a 4, gli elementi di
sintassi nel secondo passo di codifica, che include i flag abs_level_gt3_flag, abs_level_gt5_flag,
abs_level_gt7_flag e abs_level_gt9_flag sono codificati usando i bin context coded.
Se RemCcbs diventa minore di 4 durante il secondo passo, i coefficienti rimanenti che devono
ancora essere codificati vengono codificati nel 3° passo.

Passi di codifica dei residui per i blocchi di trasformata skip

Di sopra viene mostrato il processo di codifica dei residui della trasformata skip ed il sole indica la
posizione in cui i bin context coded sono esauriti e da lì in poi tutti i bin sono codificati usando il
bypass coding. Inoltre, per un blocco non codificato in modalità BDPCM, viene applicato un
meccanismo di level mapping alla codifica dei residui di trasformata skip finché non viene
raggiunto il numero massimo di bin context coded.

- Modalità Palette

Nell'H.266, la modalità palette può essere usata per codificare contenuti sintetici in tutti i formati di
chroma supportati nel profilo 4:4:4 (ovvero 4:4:4, 4:2:2, 4:2:0 e monochromatico). Quando viene
abilitata la modalità palette, viene trasmesso un flag a livello di CU se la dimensione del CU è
minore o uguale a 64x64 ed il numero di sample nel CU è maggiore di 16. Considerando che
applicare la modalità palette su piccoli CU introduce un vantaggio di codifica non significativo e
porta una maggiore complessità sui piccoli blocchi, questa viene disabilitata per tutti i CU minori o
uguali a 16 sample. Un CU (Coding Unit) codificato con la modalità palette viene trattato come una
modalità di predizione in più oltre alla predizione intra, a quella inter ed alla modalità IBC (Intra
Block Copy). Se viene utilizzata la modalità palette, i valori di sample nel CU sono rappresentati da
un gruppo di valori di colore rappresentativi e, questo gruppo, è chiamato "palette". Per le posizioni
con valori di sample vicini ai colori di palette, vengono segnalati gli indici di palette. È inoltre
possibile specificare un sample che è fuori dalla palette segnalando un simbolo di escape. Per i
sample all'interno del CU che sono codificati usando il simbolo di escape, i valori sono segnalati
direttamente usando (possibilmente) i valori quantizzati.
Esempio di un blocco codificato in modalità palette

Il simbolo di escape è binarizzato con il processo di binarizzazione Exp-Golomb di 5° ordine


(EG5). Per codificare la palette, viene mantenuto un predittore di palette; questo viene inizializzato
a 0 all'inizio di ogni slice per il caso non wavefront. Nel caso WPP, il predittore di palette all'inizio
di ogni riga CTU è inizializzato al predittore derivato dal primo CTU nella precedente riga CTU in
modo che lo schema di inizializzazione tra i predittori di palette e la sincronizzazione CABAC sono
unificati. Per ogni entry nel predittore di palette, viene segnalato un flag di ri-utilizzo per indicare se
è parte della palette corrente nel CU. I flag di ri-utilizzo sono inviati usando la codifica run-length
di zero, dopodiché viene segnalato il numero di nuove entry della palette ed i valori delle
componenti per le nuovi entry di palette. Dopo l'encoding dei CU codificati con la palette, il
predittore di palette viene aggiornato usando la palette corrente. Le entries del precedente predittore
di palette che non sono ri-utilizzate nella palette corrente vengono aggiunte alla fine del nuovo
predittore di palette, finché la grandezza massima consentita viene raggiunta. Viene segnalato un
escape flag per ogni CU per indicare se i simboli di escape sono presenti nel CU corrente e, se lo
sono, la tabella palette viene aumentata di uno e l'ultimo index è assegnato al simbolo di escape. In
maniera simile al gruppo di coefficienti (CG) usato nella codifica dei coefficienti di trasformata, un
CU codificato con la modalità palette è diviso in più gruppi di coefficienti basati sulle linee, ognuno
che consiste in m sample (m=16), dove i valori di index di palette ed i colori quantizzati per la
modalità escape sono encodati/parsati in maniera sequenziale per ogni CG. Così come nell'H.265,
possono essere applicate le scansioni orizzontali o verticali trasverse per scansionare i sample.
Scanning basato sui sotto-blocchi per la palette: orizzontale (sinistra) e verticale (destra)

Per ogni posizione di sample, viene segnalato un bin context coded run_copy_flag = 0 per indicare
se il pixel è della stessa modalità della posizione di sample precedente, cioè se il sample
precedentemente scansionato ed il sample attuale sono entrambi di tipo COPY_ABOVE o se il
sample precedentemente scansionato e quello attuale sono entrambi di tipo INDEX e dello stesso
valore di index, altrimenti viene segnalato run_copy_flag = 1. Se il sample corrente ed il sample
precedente sono di modalità diverse, viene segnalato un bin context coded
copy_above_palette_indices_flag per indicare il tipo del sample corrente, cioè INDEX o
COPY_ABOVE. Dunque, il decoder non deve parsare il tipo se il sample è nella prima riga
(scansione trasversa orizzontale) o nella prima colonna (scansione trasversa verticale) visto che la
modalità INDEX è usata di default. Allo stesso modo, il decoder non deve parsare il tipo se il tipo
precedentemente parsato è COPY_ABOVE. Dopo che la codifica di palette dei sample è stata
effettuata in un passo di codifica, i valori di index (per la modalità INDEX) ed i colori escape
quantizzati vengono raggruppati e codificati in un altro passo di codifica usando la codifica di
bypass CABAC. Questo tipo di separazione dei bin context coded e dei bin bypass coded può
migliorare il throughput all'interno di ogni linea CG. Per gli slice con doppio albero luma/chroma,
la palette è applicata sul luma (componente Y) e sul chroma (componenti Cb e Cr) in maniera
separata, con le entry della palette di luma che contengono solo i valori Y e quelle della palette di
chroma che contengono sia i valori Cb che Cr. Per gli slice di un albero singolo, la palette è
applicata su Y, Cb e Cr assieme, cioè ogni entry nella palette contiene i valori di Y, Cb e Cr, a meno
che il CU sia stato codificato usando l'albero duale locale, in tal caso la codifica del luma e del
chroma viene gestita separatamente. In questo caso, se i blocchi di luma e chroma corrispondenti
sono codificati usando la modalità palette, la loro palette è applicata in modo simile al caso a doppio
albero. Per gli slice codificati col doppio albero, la grandezza del predittore di palette massima è 63
e la grandezza della tabella di palette massima per la codifica del CU corrente è 31. Per gli slice
codificati col doppio albero, la grandezza massima del predittore e della tabella di palette è
dimezzata, cioè la dimensione massima del predittore è 31 e la grandezza massima della tabella è 15
sia per la palette di luma che di chroma. Per quanto riguarda il deblocking, il blocco codificato con
la palette sui lati di un confine di blocco non è sottoposto a de-blocking.

- Modalità palette per contenuti non 4:4:4

La modalità palette nell'H.266 è supportata per tutti i formati di chroma in maniera simile a quella
dell'H.265. Per i contenuti non 4:4:4, vengono applicate 3 customizzazioni:
1) Quando vengono segnalati i valori di escape per una posizione di sample data, se la posizione di
sample ha solo la componente di luma ma non la componente di chroma a causa del chroma
subsampling, allora viene segnalato solo il valore di escape del luma.

2) Per un blocco ad albero duale locale, la modalità palette è applicata al blocco nello stesso modo
in cui viene applicata al blocco di un singolo albero, ma con due eccezioni: la prima è che siccome
il blocco dell'albero duale locale contiene solo la componente di luma (o chroma), il processo di
aggiornamento del predittore utilizza il valore segnalato della componente di luma (o chroma) e
riempie la componente di chroma (o luma) "mancante" con un valore di default. La seconda è che la
massima dimensione del predittore di palette rimane 63 (visto che lo slice è codificato usando un
albero singolo) ma anche la dimensione massima della tabella di palette per il blocco di
luma/chroma viene mantenuta a 15 (visto che il blocco è codificato usando una palette separata).

3) Per la modalità palette nel formato monocromatico, il numero di componenti di colore nel blocco
codificato con la palette è 1 invece che 3.

- Algoritmo dell'encoder per la modalità palette

Lato encoder, vengono effettuati 3 step per produrre la tabella di palette per il CU corrente.

1° Step:
Per prima cosa, per derivare le entry iniziali nella tabella di palette del CU corrente, viene applicato
un clustering K-means semplificato. La tabella di palette del CU corrente è inizializzata come
vuota. Per ogni posizione di sample nel CU, viene calcolato il SAD tra questo sample ed ogni entry
della tabella di palette e viene ottenuto il SAD minimo tra tutte le entry della tabella di palette. Se il
SAD minimo è più piccolo del limite di errore predefinito chiamato errorLimit, allora il sample
corrente viene clusterizzato assieme alle entry della tabella di palette con il SAD minimo,
altrimenti, viene creata una nuova entry di tabella di palette. Il threshold errorLimit è dipendente dal
QP ed è recuperato da un lookup table contenente 57 elementi che copre l'intero range QP. Dopo
che tutti i sample del CU corrente sono stati processati, le entry di palette iniziali sono ordinate
secondo il numero di sample clusterizzati assieme con ogni entry di palette ed ogni entry dopo la
31° entry viene dimenticata.

2° Step:
Nel secondo step, i colori della tabella di palette iniziale vengono aggiustati considerando due
opzioni: usando il centroide per ogni cluster dal 1° Step, oppure usando uno dei colori di palette nel
predittore di palette. L'opzione con il costo di rate-distortion minore viene selezionata come colori
finali della tabella di palette. Se un cluster ha solo un singolo sample e l'entry di palette
corrispondente non è nel predittore di palette, il sample corrispondente è convertito in un simbolo di
escape nello step successivo.

3° Step:
Una tabella di palette così generata contiene alcune nuovi entry dai centroidi dei cluster del 1° Step
ed alcune entry dal predittore di palette, quindi questa tabella viene riorganizzata ancora in modo
che tutte le nuove entry (cioè i centroidi) siano messe all'inizio della tabella, seguite dalle entry del
predittore di palette.

Data la tabella di palette del CU corrente, l'encoder seleziona l'indice di palette di ogni posizione di
sample nel CU e, per ogni posizione di sample, questo controlla il costo di rate distortion di tutti i
valori di index corrispondenti alle entry della tabella di palette ed anche quelli corrispondenti ai
simboli di escape e poi seleziona l'indice con il costo minore. Dopo aver deciso la index map del
CU corrente, viene applicata l'ottimizzazione di rate distortion trellis per cercare i valori migliori di
run_copy_flag e run type per ogni posizione di sample comparando il costo di rate distortion di 3
opzioni: la stessa della posizione precedentemente scansionata, COPY_ABOVE ed INDEX.
Quando vengono calcolati i valori di SAD, i valori di sample sono scalati ad 8bit a meno che il CU
non sia codificato in modalità lossless, in tal caso viene utilizzato il bit depth di input per calcolare
il SAD. Inoltre, nel caso di encoding lossless, solamente il rate è utilizzato negli step di
ottimizzazione di rate distortion menzionati sopra (perché l'encoding lossless non ha alcuna
distorsione).

- ACT – Adaptive Color Transform

Nell'H.266, per migliorare l'efficienza di codifica del 4:4:4, è stata adottata l'ACT (Adaptive Color
Transform). L'ACT effettua una conversione di spazio di colore in loop nel dominio dei residui di
predizione convertendo adattivamente i residui dallo spazio di colore in ingresso allo spazio YcgCo.

Rappresentazione grafica della decodifica con ACT

L'immagine di sopra mostra la decodifica con l'ACT applicato. I due spazi colore sono selezionati
in maniera adattiva segnalando un flag ACT a livello di CU. Quando il flag è pari ad 1, i residui del
CU sono codificati nello spazio YcgCo, altrimenti i residui del CU vengono codificati nello spazio
di colore originale. Non solo, per i CU inter ed IBC, l'ACT viene abilitato solo quando c'è almeno
un coefficiente non nullo (non zero) nel CU. Per i CU intra, invece, l'ACT viene abilitato solo
quando le componenti di chroma selezionano la stessa modalità di predizione intra della
componente di luma, cioè la modalità DM.

- Modalità ACT

La modalità ACT supporta la codifica sia lossless che lossy a seconda del flag lossless (cioè
cu_transquant_bypass_flag), tuttavia, non ci sono flag segnalati nel bitstream per indicare se è stata
applicata una codifica lossy o lossless, dunque viene applicata una trasformata YcgCo-R come ACT
per supportare sia i casi lossy che quelli lossless.
Conversione in avanti: da GBR a YCgCo Conversione all’indietro: da YCgCo a GBR
Co = R-B; t = Y – (Cg>>1)
t = B + (Co>>1); G =  Cg + t
Cg = G – t; B = t – (Co>>1)
Y = t + (Cg>>1); R = Co + B

Visto che la trasformata YcgCo-R non è normalizzata, per compensare il cambiamento di range
dinamico dei segnali residui prima e dopo la trasformata del colore, vengono applicati degli
aggiustamenti QP di (-5, 1, 3) ai residui di trasformata della componenti Y, Cg e Co. Il parametro di
quantizzazione aggiustato ha effetto solo sulla quantizzazione e sulla quantizzazione inversa dei
residui nel CU, mentre per gli altri processi di codifica (tipo il deblocking) viene applicato il QP
originale. Non solo, siccome le trasformate in avanti ed inversa del colore hanno bisogno di
accedere ai residui di tutte e 3 le componenti, la modalità ACT viene sempre disabilitata per le
partizioni ad albero separate e per la modalità ISP in cui la grandezza del blocco di predizione delle
diverse componenti del colore è diverso. Quando viene applicata la modalità ACT, la TS (Transform
Skip) e la BDPCM (Block Differential Pulse Coded Modulation) – che sono estese per codificare i
residui di chroma – vengono abilitate.

3.9) Comparazione MPEG-1 vs MPEG-2 vs MPEG-4 Visual vs H.265 vs H.266

Per misurare l'efficienza di codifica dei codec è stato preso un masterfile lossless non compresso
3840x2160 23.976fps progressivo 4:2:0 yv12 8bit planar ed è stato encodato allo stesso bitrate (25
Mbit/s) e GOP in MPEG-1, MPEG-2, MPEG-4 Visual (aka XVID), H.265 ed H.266, dopodiché è
stato utilizzato l'SSIM per ottenere il valore relativo alla qualità degli encode individuali. L'SSIM
(Structural Similarity Index Measure) è un metodo di predizione della qualità percepita e viene
utilizzato per misurare le somiglianze tra le due immagini (quella originale e quella encodata).
L'SSIM è una metrica completamente referenziata, cioè la misura o predizione della qualità
dell'immagine è basata, appunto, sull'immagine iniziale lossless non compressa come riferimento.
L'SSIM è un modello basato sulla percezione che considera la degradazione di un immagine come
cambiamento percepito nell'informazione strutturale, incorporando anche il fenomeno della
percezione usando elementi di masking sia del luma (immagine in se per se, in bianco e nero) che
del chroma (componente chromatica dell'immagine). L'informazione strutturale è l'idea che i pixel
abbiano una forte inter-dipendenza, specialmente quando sono vicini nello spazio. Avere queste
forti dipendenze significa che vengono mantenute le informazioni importanti relative alla struttura
degli oggetti nella scena. L'SSIM è calcolato su più "finestre" dell'immagine. La misura tra due
finestre, che chiamiamo x ed y, di grandezza comune NxN è:

dove μx è la media di x, μy è la media di y, è la varianza di x, è la varianza di y, σxy è la


covarianza di x ed y, sono le due variabili usate per stabilizzare la divisione con un
denominatore debole, L è il range dinamico dei valori dei pixel (generalmente 2 alla bpp -1, dove
"bpp" indica Bit Per Pixel) ed infine k1=0.01 e k2=0.03. La formula è basata su 3 misure di
comparazione tra i sample di x ed y: luma (l), contrasto (c) e struttura (s). Le funzioni di
comparazione individuali sono:
ed anche c3 = c2/2; l'SSIM è la combinazione pesata di queste misure comparative:

Mettendo i pesi α, β, γ, uguali ad 1 la formula può essere ridotta. L'SSIM soddisfa il principio di identità
degli indiscernibili (ovvero un principio che dice che se non c'è modo di distinguere due enti, allora sono in
realtà un unico ente) e le proprietà di simmetria. Una volta applicata la misurazione, l'SSIM restituisce
un valore decimale tra 0 ed 1, dove 1 indica che ci troviamo difronte a due data set esattamente
identici e quindi abbiamo una struttura di similarità perfetta, mentre 0 indica che non c'è similarità.
Dunque, utilizzando l'SSIM è possibile vedere se la qualità risultante di un'immagine è migliore o
peggiore di quanto ci si aspetta. Dopo un encoding di 200 frame, i risultati sono:

MPEG-1 MPEG-2 XVID H.264 H.265 H.266


191.187811 191.402233 192.064741 193.297756 194.214381 194.249329
Se andiamo ad analizzare in particolare solamente H.265 ed H.266 abbiamo:

Ad eccezione di alcuni punti, il punteggio dell'H.266 risulta superiore a quello dell'H.265, riuscendo
ad ottenere quindi una fedeltà dell'immagine maggiore rispetto ad esso. C'è da dire che la differenza
è assottigliata dal fatto che lo standard H.265 è ormai stabilito ed affermato, quindi gli encoder
attualmente disponibili come x265 sono maturi, al contrario per quanto riguarda l'H.266 si ha
ancora ampio margine di miglioramento, ma nonostante questo il punteggio risulta più alto. Se
includiamo adesso l'H.264 encodato con x264 abbiamo:

Come appare chiaramente dall'immagine, l'H.264 si avvicina molto più all'H.265 che non all'H.266
ed infatti in alcuni punti risulta addirittura avere una qualità maggiore in quanto viene preferita
l'edge preservation e la grain retention che potrebbero creare dei leggeri artefatti ai limiti dei blocchi
di trasformata rispetto ad un'immagine con meno artefatti ma più blurrata come quella dell'H.265.
In generale, comunque, l'H.265 ottiene comunque performance superiori rispetto all'H.264.
Andando verso codec inferiori e con più anni sulle spalle come l'xvid, la differenza con un codec
moderno capace di gestire risoluzioni come quella di questo test (UHD) appare chiaro il divario:
L'xvid, a parità di bitrate, rimane inferiore in quasi ogni scena, ma d'altra parte non è stato fatto per
gestire risoluzioni così alte come l'UHD a bitrate così bassi come 25 Mbit/s.

La stessa cosa vale per l'MPEG-2 che non sembra stare al passo con l'H.266 e questo è altrettanto
vero per l'MPEG-1.

Dunque è possibile notare come i nuovi strumenti di codifica implementati nell'H.266, nonostante
comportino un aumento del costo computazionale, riescano effettivamente a portare un
miglioramento delle prestazioni in termini di compressione, o, a seconda di come uno la voglia
vedere, di migliore qualità a parità di compressione rispetto agli standard precedenti ed in maniera
più pronunciata man mano che ci si allontana temporalmente dallo standard. Di seguito viene
mostrata una tabella che rappresenta alcuni dei valori singoli SSIM presi in considerazione durante
l'analisi che hanno dato vita ai grafici.
4) Utilizzo delle trasformate nei codec di codifica audio
Dopo aver trattato i vari tipi di codifica video, è giunto il momento di completare il “ciclo” della
tesi trattando la codifica audio. Analogamente a quanto visto per la codifica delle immagini fisse e
la codifica delle immagini in movimento, anche per la codifica audio si parla di codec lossy e
lossless e l'intento delle varie codifiche (a livello concettuale) è pressoché uguale a quello già
trattato precedentemente. Prima di tutto, però, è bene porre alcune premesse: un uccellino che canta,
una madre che parla al telefono col figlio od ancora una sinfonia di musica classica sono tutti
esempi di segnali audio; difatti tutto quello che sentiamo è un segnale audio ed un dato codec deve
essere in grado di poter codificare in maniera ottimale tante tipologie di segnale audio differenti,
visto che la natura del segnale è incredibilmente varia.
La rappresentazione digitale di un segnale audio non compresso, ad oggi, è pressoché identica al
formato CD sviluppato per il mondo consumer anni fa. Esistono, chiaramente, anche altri formati
tipo il DAT, ma questi sono per lo più utilizzati negli studi per lo storage ad alta qualità.
Il segnale audio nel formato CD è campionato a 44.1 kHz usando un PCM a 16bit (Pulse Core
Modulation), che risulta in un bitrate non compresso di 705.6 kbps per gli audio in modalità canale
mono ed 1.41 Mbps nella modalità canale stereo. Ad ogni modo, questi bitrate altissimi non sono
affatto positivi per la trasmissione.

– Segnali musicali

I segnali musicali sono tipicamente armonici e sono dati da:

dove f() è la frequenza fondamentale (picco), cm è l'ampiezza, è la fase ed a(t) è la fascia.


La struttura armonica di uno strumento musicale è costituita da una serie di ampiezze
delle armoniche relative alla frequenza fondamentale (misurata in dB).
Le differenze nella struttura armonica e la fascia rendono i suoni diversi.

– Segnali parlati

I blocchi di costruzione di base di una lingua sono detti “fonemi”. Un fonema può essere di “voce”
se generato da corde vocali, o “non di voce” se le corde vocali non sono coinvolte.
Quando viene progettato un codificatore di segnali parlati, solitamente, viene prestata molta più
attenzione ai fonemi “di voce” rispetto a quelli “non di voce” in quanto generalmente molto più
presenti. Il tratto vocale è generalmente dato da un sistema lineare che varia nel tempo con una
funzione razionale ed “all-pole” nella quale p è tipicamente 8-12:

La descrizione matematica del segnale generato dalle corde vocali è un flusso di impulsi quasi
periodico, nel senso che gli intervalli tra gli impulsi successivi e le ampiezze di impulsi differenti
non sono esattamente costanti.
Il reciproco dell'intervallo medio tra gli impulsi successivi è chiamato “picco di frequenza” ed è
caratteristico per ogni persona. Il picco di un uomo adulto si aggira generalmente tra gli 80 ed i 120
Hz, mentre per una donna adulta si aggira tra i 150 ed i 300 Hz. Le due equazioni riportate di sopra
sono combinate in un modello a breve periodo per i segnali parlati:

Questo modello è chiamato LPC (Linear Predective Coding) ed è infatti un modello auto-regressivo
con y[n] come componente di errore in questa predizione.

– Organizzazione di un Encoder Audio

Di seguito viene riportato un template generale che offre un esempio di come la compressione audio
sia svolta a livello pratico:

Per prima cosa, il dato audio è partizionato in molteplici frame, da 2 a 50 ms di durata, a seconda
dell'algoritmo. Il segnale audio digitale è poi passato simultaneamente al blocco “time-frequency”
ed a quello “psychoacoustic”. Il blocco “time-frequency” trasforma il dato audio e dà in output una
rappresentazione di coefficiente di trasformata dei valori di ampiezza. Il blocco “psychoacoustic”
sfrutta l'irrilevanza percettiva tra il dato audio ed i masking threshold di output. Questi threshold
definiscono il livello di noise consentito, in modo da mantenere questo noise inudibile.
Vengono utilizzati nel processo di allocazione dei bit (blocco “bit allocation”) per controllare la
quantizzazione dei coefficienti di trasformata in modo che il noise di quantizzazione non ecceda i
threshold. Le ridondanze statistiche rimanenti sono poi eliminate da un algoritmo di codifica
entropica che comprime la rappresentazione binaria del dato audio.
Infine, i coefficienti di trasformata codificati in forma binaria – assieme alle informazioni
secondarie necessarie – sono trasmessi al channel.
Il processo di decodifica è l'inverso, ma è molto più semplice visto che è solamente necessario
identificare la rappresentazione binaria dei coefficienti quantizzati ed estrarre le informazioni
secondarie necessarie, in modo da ricostruire il dato audio dai coefficienti quantizzati.

– Fondamenti del modello psico-acustico


Il primo passo per rimuovere le informazioni dal segnale audio originale è fatto studiando come
l'analizzatore delle frequenze temporali umano – più comunemente detto “orecchio” – tratta i
segnali audio. L'output di questo primo passo (o processo) sono i “masking threshold” che indicano
il livello di distorsione tollerato in modo da mantenere le informazioni rimosse inudibili. Questa
“simulazione” della risposta dell'orecchio umano ai suoni è chiamata, appunto, “modello psico-
acustico” ed esplora i limiti dell'abilità umana di percepire suoni e distorsione,
in modo da comprimere efficientemente il segnale audio.
Ad ogni modo, i risultati ottenuti nell'area di ricerca della psico-acustica
sono lungi dall'essere perfetti e teoreticamente derivati.

– L'orecchio

L'orecchio umano consiste nell'orecchio esterno, l'orecchio interno e l'orecchio medio.


Nell'orecchio esterno, troviamo la “pinna” che fornisce informazioni sulla direzione dell'origine
del suono; aggiunge questa informazione all'informazione di pressione del suono
decodificata dal cervello.
La parte esterna consiste inoltre nel canale dell'orecchio, che amplifica i suoni che vi passano
a certe frequenze (ricordiamo che l'orecchio umano ha un range di percezione sonoro che varia dai
20 ai 20.000 Hz circa, che si abbassa progressivamente con l'età).
La parte media è una cavità piena d'aria contenente tre piccole ossa (martello, incudine e staffa) che
formano un'impedenza meccanica per “collegare” correttamente la parte esterna con la parte interna
ripiena di liquido. L'obiettivo dell'orecchio medio è di trasferire nel modo più efficiente possibile
tutta l'energia data dalle vibrazioni alla parte interna.
La parte interna è l'unica parte dell'orecchio che gli scienziati non hanno ancora compreso appieno
per poter dare agli ingegneri un modello esatto di percezione uditiva umana.
A grandi linee, consiste nel meccanismo di bilanciamento (equilibrio) del corpo ed è formato
da tre canali semi-circolari e l'organo di processo uditivo conosciuto come “cochlea”.
La parte interna è divisa da due membrane, conosciute come la membrana di Reissner
e la membrana di base.

– Il threshold uditivo assoluto

La definizione di threshold assoluto dell'udito è dato dalla quantità di energia richiesta in un tono
puro, in modo da essere percepita da un uditore in un ambiente privo di noise.
Nel modello psico-acustico completo viene utilizzato un “threshold assoluto” atto ad evitare un
“under-coding”, ovvero evitare di mantenere informazioni al di sotto di tale livello (threshold),
visto che sarebbero irrilevanti per la qualità percepita del segnale audio.
Un'approssimazione di threshold uditivo assoluto è data da:

Il punto più basso della curva è 4 kHz e dato che il livello di playback è sconosciuto a priori,
lo schema del codificatore audio solitamente eguaglierà questo punto con l'energia in un seno a 4
kHz, con un ampiezza di +/- 1bit dell'ampiezza del segnale audio.

– Bande critiche

Le bande critiche modellano come come l'orecchio (ed il cervello) eseguono l'analisi spettrale e

rappresentano il punto in cui l'orecchio non può distinguere due frequenze differenti nella stessa
banda critica. Questo effetto ha la sua origine nella membrana di base, che utilizza diverse parti
della sua superficie a seconda della frequenza. Il cervello può decodificare più facilmente le
informazioni ricevute alle estremità, dove sono decodificate le frequenze più basse. Quando si ha a
che fare con bande critiche, è conveniente parlare di distanze di bande critiche
e la distanza di una banda critica è misurata in un “bark” e, per convertire da frequenza a bark,
si utilizza la seguente formula:
Banda – Frequenza centrale (Hz) – Intervallo (Hz)
1 – 50 - -100
2 – 150 - 100-200
3 – 250 - 200-300
4 – 350 - 300-400
5 – 450 - 400-510
6 – 570 - 510-630
7 – 700 - 630-770
8 – 840 - 770-920
9 – 1000 - 920-1080
10 – 1170 - 1080-1270
11 – 1370 - 1270-1480
12 – 1600 - 1480-1720
13 -1850 - 1720-2000
Banda – Frequenza centrale (Hz) – Intervallo (Hz)
14 – 2150 - 2000-2320
15 – 2500 - 2320-2700
16 – 2900 - 2700-3150
17 – 3400 - 3150-3700
18 – 4000 - 3700-4400
19 – 4800 - 4400-5300
20 – 5800 - 5300-6400
21 – 7000 - 6400-7700
22 – 8500 - 7700-9500
23 – 10500 - 9500-12000
24 – 13500 - 12000-15500
25 – 19500 -15500-

La banda delle bande critiche diventa più grande all'aumentare della frequenza, poiché, come detto
prima, la membrana di base utilizza per le frequenze più alte la sua parte interna meno sensibile
invece delle estremità più sensibili.

– Banda equivalente rettangolare

Un problema delle bande critiche è celato nella loro derivazione sperimentale, che è effettuata con
una maschera a piccola banda ed un tono sonda. Il problema dimostra infatti che tra il segnale sonda
e la maschera si possono verificare effetti come i prodotti di inter-modulazione.
Un modello migliore per le bande di frequenza è l'ERB (Equivalent Rectangular Bandwidth) e,
a livelli di pressione sonora moderati, la conversione da frequenza ad ERB è:

dove f è la frequenza centrale in Hz. Il numero di ERB sotto ogni frequenza è:

dove f è in Hz. La differenza principale tra le bande critiche e l'ERB è che quest'ultimo è in grado di
evitare gli errori che si verificano per le bande critiche alle frequenze più basse (inferiori a 500 Hz).

– Masking Simultaneo
Il masking è un fonema che si verifica quando un'eccitazione di una certa forza sulla membrana di
base, con una banda critica, blocca la trasmissione di un segnale più debole. Questo è un fatto molto
importante per il design del modello psico-acustico, visto che ci permette di rimuovere informazioni
che sono “mascherate” da un segnale più forte. Il masking simultaneo si presenta in due forme:
“tono di masking noise”, ovvero il noise threshold in cui un forte tono originato dal centro di una
banda critica “maschera” il noise ovunque all'interno della banda critica.
Il secondo è il “masking noise di tono”, ovvero il threshold di tono in cui un forte noise originato
dal centro di una banda critica “maschera” i toni ovunque all'interno della banda critica.
Potenzialmente, il masking (sia questo di tono o di noise) può avvenire anche in altre bande critiche
ed in questo caso viene definito “masking di inter-banda”.

Dove x è in bark. Il noise masking threshold è dato invece da:

dove ET è l'energia della maschera di tono e B è il numero di banda critica.


Il masking threshold di tono, invece, è dato da:

dove EN è il noise di banda critica e K è un parametro che viene generalmente settato tra 3 e 5.

– Masking Temporale

Un colpo emesso da una grancassa è un ottimo esempio di masking temporale.


Questo tipo di masking si verifica quando il threshold udibile è innalzato momentaneamente dallo
“shock”; la funzione di decodifica del cervello è parzialmente paralizzata da questo evento durante
un corto periodo di pre-masking (circa 5ms), dal periodo di evento stesso
e un periodo di post-masking più lungo (circa 50-300ms).

– Entropia percettiva

L'entropia percettiva (PE – Perceptual Entrophy) è una combinazione di principi di masking


e quantizzazione del segnale che definisce una misura per il limite teoretico della compressibilità
di un segmento audio o, in altre parole, il contenuto minimo di informazione che il cervello può
decodificare senza notare una perdita di qualità.
L'algoritmo di Entropia Percettiva funziona principalmente come segue:

1) Trasforma il segnale nel dominio delle frequenze.


2) Ottiene il masking threshold utilizzando le regole percettive.
3) Calcola il numero minimo di bit richiesti per quantizzare un segmento audio
senza introdurre noise udibile.
– Modello Psico-acustico MPEG

Il metodo di compressione più conosciuto ed utilizzato, ad oggi, è lo standard MPEG, anche per
quanto riguarda la codifica audio. Ci sono state tante proposte durante gli anni per quanto riguarda
la codifica audio ed una delle più conosciute utilizza la trasformata di Wavelet; al contrario, MPEG,
nei suoi standard audio, utilizza un filterbank polifase ed i due modelli psico-acustici che prenderò
di seguito in esame forniscono un ottimo esempio
del funzionamento dei modelli psico-acustici attuali.

1) Modello Psico-acustico I

Il primo modello utilizza 512 campioni per il Layer 1 che produce un “nuovo” vettore da 384
campioni. Per i Layer 2 e 3 vengono invece utilizzati 1024 campioni. Ad ogni modo, l'analisi è di
1152 campioni per i Layer 2 e 3, quindi alcuni campioni “decadono” nel modello 1 durante il
calcolo completo. Questi campioni sono trasformati attraverso il dominio delle frequenze
utilizzando la trasformata di Fourier veloce, già analizzata in precedenza nella prima parte della tesi.
Dopodiché, i campioni sono compensati per effetti di bordo attraverso una finestra di Hann pesata.

(funzione di Hann sulla sinistra e la sua risposta in frequenza a destra)

La finestra di Hann è una combinazione lineare di finestre rettangolari modulate

Dalla formula di Eulero:

A causa delle proprietà di base della trasformata di Fourier, il suo spettro è:

con lo spettro della finestra rettangolare:

(il fattore di modulazione svanisce se le finestre sono shiftate di tempo attorno allo zero)
La funzione di Hann, infatti, è proprio una funzione finestra discreta ed è difatti utilizzata come
funzione finestra per selezionare un sotto-insieme di campioni per poter eseguire la trasformata di
Fourier od altri calcoli. Ad ogni modo, una volta eseguite le varie operazioni sui campioni, è il
momento di calcolare lo spettro discreto di Bark e questo è fatto sommando l'energia in ogni banda
critica e separando i valori spettrali in componenti “di tono” e “non di tono”. Le componenti di tono
sono individuate ricercando i picchi locali nello spettro di potenza, e le componenti non di tono
sono situate nell'indice più vicino alla media geometrica della banda critica. Le componenti non di
tono sono i valori spettrali rimanenti sommati in ogni banda critica. Fatto questo, viene applicata al
segnale audio una funzione di maschera empiricamente determinata, che calcola il noise masking
threshold ed incorpora inoltre il threhsold uditivo assoluto. Viene poi calcolato masking threshold in
ogni banda critica ed infine viene derivato il rapporto segnale-maschera dividendo l'energia di
segnale totale in ogni banda dal masking threshold minimo corrispondente.

2) Modello Psico-acustico II

Il modello pisco-acustico MPEG II è una versione più avanzata del modello originale che utilizza
1024 campioni per tutti e tre i Layer. I due modelli hanno molte cose in comune e, dunque, all'atto
pratico, è molto più semplice esplicare il secondo modello partendo dalle differenze che ha rispetto
al primo. Per ogni analisi nel Layer 2 e 3, il modello computa due finestre con l'analisi psico-
acustica corrispondente e poi combina i risultati utilizzando il più alto dei rapporti segnale-
maschera per ogni banda ed il più basso dei noise masking threshold per ogni banda. Invece di
separare i valori in “di tono” e “non di tono”, questo modello computa un indice di tonalità che
misura ogni componente rispetto alle sue caratteristiche di tono. L'indice è poi utilizzato per
l'interpolazione tra il tono di masking noise ed il masking noise di tono. Il noise masking threshold
viene poi calcolato da una funzione incorporata con il threshold uditivo assoluto. Infine, il masking
minimo altro non è che i threshold calcolati dalla media dei masking threshold in ogni sotto-banda
di overlap con la banda critica attuale.

– Analisi Tempo-Frequenza

L'analisi tempo-frequenza in uno schema di codifica audio trasforma i dati audio nel dominio delle
frequenze in modo da rappresentare l'informazione con i coefficienti di trasformata invece dei valori
di ampiezza, dato che è possibile distribuire l'energia del segnale in questi coefficienti e decorrelare
il segnale, in modo analogo a come accadeva nella codifica delle immagini fisse ed in movimento.
Il modo più comune per farlo è quello di utilizzare una trasformata unitaria quale, ad esempio, la
DCT (Trasformata Discreta del Coseno) che risulta essere un'ottima trasformata non solo per i
codec visti precedentemente nel campo visivo, ma anche per quanto riguarda alcuni tipi di segnale
audio! Come sappiamo, però, le trasformate unitarie non offrono la possibilità di avere una
risoluzione temporale sufficiente, ma, d'altro canto, forniscono stime spettrali ad alta risoluzione,
che compensano questo punto a loro sfavore. Un altro modo per eseguire l'analisi tempo-frequenza
sono i filterbank con la trasformata di Wavelet od altre trasformate.

– Quantizzazione scalare

1) Quantizzazione uniforme

Nella tecnica di quantizzazione uniforme, il range di valori in input possibili viene diviso in bande
di uguale grandezza, in modo che i valori in input appartenenti alla stessa banda siano collegati
ad un valore scalare univoco del set di quantizzazione.
Come esempio, se volessimo quantizzare uniformemente l'intervallo tra 1 e 2 con 2 bit,
dovremmo ricevere 2^2 = 4 possibili valori scalari tra questi due valori, ovvero 1, 1.33, 1.66 e 2.
La quantizzazione uniforme è un metodo molto semplice (ma inefficiente) di quantizzare i
coefficienti di trasformata, dato che molti valori rimangono inutilizzati. Quando vogliamo
quantizzare i coefficienti di trasformata che sono molto deboli, abbiamo il problema che ogni valore
è quantizzato a zero e questo può essere risolto utilizzando la tecnica di quantizzazione
non uniforme.

2) Quantizzazione non uniforme

Per avere una quantizzazione “precisa” per i segnali deboli e “grossolana” per i segnali più forti e
per avere un noise di quantizzazione più proporzionato al segnale, dobbiamo usare una tecnica di
quantizzazione non uniforme. Ci viene in aiuto, in questo caso, la quantizzazione con compressione
a funzione logaritmica che comprime il segnale con una funzione logaritmica appropriata, quantizza
uniformemente l'output ed espande il segnale con l'inversa della funzione logaritmica usata in
origine. L'Europa ed il Nord America utilizzano due formule leggermente differenti che raccolgono
i tre passaggi elencati precedentemente in una formula di “compandorizzazione”.
In Europa la formula è la seguente:

dove A è una costante positiva (il valore standard è 87.6), x è il valore in input ed y è il valore
quantizzato in output.

– Quantizzazione vettoriale

La quantizzazione vettoriale è un'estensione della quantizzazione scalare, nel senso che, in questo
caso, stiamo cercando un collegamento tra un vettore in input ed un “libro di codice” di vettori di
quantizzazione. La ricerca per il collegamento migliore è un processo esaustivo se è eseguito con
l'intento di trovare il miglior collegamento possibile testando tutte le combinazioni. Dunque,
l'algoritmo di ricerca della quantizzazione vettoriale cerca di identificare ed eliminare i pattern
meno probabili e cerca di individuare un collegamento semi-ottimale. Questo può essere fatto con
un test di errore quadratico medio pesato tra i vettori in input ed il set di vettori quantizzati che può
stoppare il test se la somma dell'errore quadratico medio tende a violare il threshold di errore
quadratico medio totale predefinito. Quindi è possibile evitare di compandorizzare l'intero vettore
quando sappiamo che fallirà.

– Allocazione di bit parametrica

A questo punto, abbiamo presentato i primi passaggi di uno schema di codifica audio. Abbiamo ora
la rappresentazione trasformata del dato audio e dei masking threshold e, nell'allocazione di bit
parametrica, queste saranno combinate. Il processo di allocazione di bit regola la quantizzazione dei
coefficienti di trasformata con l'aiuto dei masking threshold dal modello psico-acustico. L'obiettivo
è di assottigliare la distorsione di quantizzazione sui coefficienti di trasformata in modo da far
rimanere il tutto inudibile dopo la compressione. L'allocazione di bit parametrica è stata ideata
principalmente per essere utilizzata dall'AC-3 ed è basata sui principi psico-acustici. Combina
inoltre i principi sia dell'adattamento in avanti che di quello indietro. L'adattamento in avanti
significa che l'encoder computa i bit e poi trasmette i bit di assegnamento come informazioni
secondarie in modo da consentire una maggiore flessibilità nell'algoritmo di allocazione.
L'adattamento indietro, invece, ha anch'esso l'encoder che computa i bit, ma invece di trasmettere i
bit di assegnamento, questi sono ri-computati dal decoder, salvando bit importanti.
I bit che sono stati risparmiati, dunque, possono essere utilizzati per encodare i coefficienti stessi!
Entrambe le “strategie” condividono caratteristiche che lo schema di allocazione di bit parametrico
cerca di incorporare. L'allocazione è costruita con parametri che controllano la forma della curva di
masking e, dunque, che controllano i bit. Dato che il segnale audio potrebbe essere ristretto in modo
da non avere dei bit sufficientemente ottimizzati utilizzando tali parametri, vengono trasmessi
codici di bit-stream aggiuntivi. Questi codici di bit-stream portano informazioni sulle differenze tra
la forma della curva di masking controllata dai parametri ed un'analisi psico-acustica indipendente
che aggiunge i necessari aggiustamenti alla curva. I delta, come vengono chiamati i codici di bit-
stream, possono essere di varia lunghezza, consentendo all'encoder di utilizzare solamente questo
spazio per apportare i cambiamenti necessari alla curva di masking.

– Struttura di dati Zerotree interna

Visto che con segnali deboli riceviamo valori di coefficienti vicini a zero, la probabilità di ottenere
uno zero dopo la quantizzazione è molto alta. Questo fatto ha spinto lo sviluppo verso l'utilizzo di
mappe di significato, ovvero una tabella di decisione binaria che ci comunica se un dato coefficiente
ha un valore di quantizzazione zero o non zero. Il costo totale di encoding di una tabella di
coefficienti di valore sopra lo zero, più la rappresentazione dei coefficienti non zero
è molto più bassa che senza la mappa di significato. Viene così usato un algoritmo di compressione
per le mappe di significato che utilizza i così detti “Zerotree” dei coefficienti di Wavelet ed,
anche se era originariamente pensata per la compressione delle immagini, i risultati possono essere
applicati alla compressione audio senza troppi problemi. Lo “Zerotree” è una struttura di dati che
marca ogni coefficiente di Wavelet con un flag che denota la sua “importanza” (il suo significato)
rispetto al threhsold scelto sul valore di coefficiente. Vengono usati 4 flag, ovvero:

1) Zerotree root, che denota che gli elementi in scala più precisa di questo elemento non sono
significativi, ma molti hanno elementi significativi a scale più “grossolane”.

2) Zero isolato, che denota che il coefficiente non è significativo, ma ha alcuni discendenti
significativi

3) Positivo significativo, che applica un segno positivo sull'elemento significativo.

4) Negativo significativo, che applica un segno negativo sull'elemento significativo.

Lo “Zerotree” consente all'encoder di concentrare i bit a disposizione solo nelle regioni significative
e questo, ovviamente, è un grande miglioramento nel processo di allocazione dei bit.
Detto questo, è il momento di andare a vedere i vari codec audio nello specifico
e come si sono evoluti nel tempo, standard dopo standard.

4.1) MPEG-1 Layer I (.mp1)

Il primo codec audio preso in esame è proprio l'MPEG-1 Layer I, più comunemente conosciuto
come “.mp1”, a causa della sua estensione. Precedentemente abbiamo visto le basi di un modello
psico-acustico, questo perché, come già accennato, l'MPEG basa la sua tecnologia
sul funzionamento del modello psico-acustico nei suoi codec
ed il primo preso in esame, il semplice .mp1, non fa esclusione.
Grazie alla psico-acustica, l'MPEG audio può ridurre significativamente il bitrate richiesto per uno
stream audio in quanto riduce (od elimina completamente) alcune parti dell'audio che deduce che
l'orecchio umano non è in grado di sentire.
Questo perché tali parti di audio potrebbero essere in frequenze per le quali l'orecchio umano è
meno sensibile, o “mascherate” da altri suoni, tipicamente più forti. Al tempo della sua creazione,
l'MPEG-1 Layer I (.mp1) venne creato in modo da avere un basso costo computazionale, in modo
da poter favorire gli applicativi in real time come le teleconferenze e consentire dunque un encoding
in real time. L'MPEG-1 Layer I (.mp1) è in grado di encodare frequenze di campionamento di 32
KHz, 44.1 KHz e 48 KHz ad un bitrate di 32, 64, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416 e
448 kbit/s ed utilizza una codifica a 32 sotto-bande. Il suo utilizzo più importante, all'epoca,
fu la sua implementazione nello standard DGC (Digital Compact Cassette) che prevedeva l'audio
in .mp1 384 kbit/s. Seppur ampiamente supportato dalla maggior parte dei riproduttori audio
e molto leggero in riproduzione, l'.mp1 è ormai caduto in disuso
ed è stato soppiantato dagli standard successivi.

4.2) MPEG-1 Layer II (.mp2)

Dopo l'mp1, è il turno dell'mp2, un codec che è stato pensato per portare una buona qualità a circa
192 kbit/s per un audio stereo. L'mp2 è un encoder che si serve del dominio del tempo ed utilizza un
filter bank a 32 sotto-bande. Il modello psico-acustico è basato sui principi di masking uditivo,
sugli effetti di masking simultaneo e sul threshold uditivo assoluto, tutti concetti già affrontati di
sopra. Come ho appena detto, l'mp2 opera sul dominio del tempo; il dominio del tempo perché mi
riferisco a come vengono effettuate analisi e quantizzazione su piccoli campioni discreti di forme
d'onda audio. Così facendo si ha un basso ritardo in quanto solo un piccolo numero di campioni
sono analizzati prima dell'encoding, al contrario di come accade, ad esempio, nello standard
successivo e famosissimo (l'mp3) che si serve del dominio della frequenza e deve, per tanto,
analizzare molti più campioni prima di decidere come trasformare ed outputtare l'audio encodato.
Per quanto riguarda il filter bank a 32 sotto-bande, questo genera 32 coefficienti di ampiezza, uno
per ogni banda di frequenza di egual grandezza dell'audio, che è largo circa 700 Hz (a seconda della
frequenza di campionamento). L'encoder poi utilizza il modello psico-acustico per determinare
quali sotto-bande contengono informazioni audio che sono meno importanti, ovvero dove la
quantizzazione sarà inudibile o, quantomeno, meno notabile. Il modello psico-acustico è applicato
utilizzando una trasformata veloce di Fourier a 1024 punti; 1024 perché dei 1152 campioni,
ne vengono ignorati 64 in cima e 64 in fondo al range di frequenza per questa analisi, visto che,
presumibilmente, non sono abbastanza significativi per poter cambiare il risultato. Il modello psico-
acustico utilizza un modello di masking determinato empiricamente per determinare quali sotto-
bande contribuiscono maggiormente al masking threshold e quanto noise di quantizzazione possono
contenere prima che questo diventi percepibile. Qualsiasi suono sotto al threshold uditivo assoluto
viene completamente eliminato ed i bit disponibili vengono assegnati ad ogni sotto-banda.
Tipicamente, le sotto-bande sono meno importanti se contengono suoni più attenuati (con meno
coefficienti) delle sotto-bande vicine (ovvero con frequenza simile) con suoni più alti (con più
coefficienti). Inoltre, le componenti di noise hanno un effetto di maschera più significativo rispetto
alle componenti di tono. Le sotto-bande meno significative sono ridotte in accuratezza dalla
quantizzazione e questo, praticamente, comporta comprimere il range delle frequenze (l'ampiezza
dei coefficienti). L'mp2 può anche utilizzare l'ISC (Intensity Stereo Coding), una forma di
joint stereo. Questo vuol dire che le frequenze sopra ai 6 KHz, di entrambi i canali sono combinate
in un singolo canale mono, ma le “informazioni secondarie di canale” sulla relativa intensità
(volume, ampiezza) di ogni canale sono preservate ed encodate separatamente nel bitstream.
In fase di playback, il singolo canale viene riprodotto tramite gli speaker destro e sinistro, con le
informazioni di intensità applicate ad ogni canale per dare l'illusione del suono stereo; questo trucco
percettivo è chiamato “irrilevanza stereo”. Sebbene tale “trucco” comporti un'ulteriore riduzione di
bitrate, in generale si preferisce mantenere un vero stereo ed utilizzare alti bitrate.

– Valutazioni finali

Esattamente come per gli altri codec, anche per i codec di codifica audio è interessante testare sul
campo la loro efficienza teorica, in modo da poter dare un giudizio completo. Per il test sono state
scelte come source dei CD a 16bit, 44.1 KHz e, per mantenere una qualità audio accettabile rispetto
a quella delle source, l'mp2 si è dovuto spingere fino a 256 kbit/s, ottenendo un peso finale di circa
1/6 rispetto all'audio wav non compresso del CD; un risultato veramente impressionante per l'epoca
della creazione di tale codec, ma del tutto inefficace ai giorni nostri, visto che l'AAC è in grado di
comprimere la stessa source utilizzando metà del peso dell'mp2 (a pari qualità). Dai test, però, è
risultato che l'mp2, per particolarissimi tipi di segnali audio, si piazza leggermente sotto a codec
come AAC ed AC3, con risultati sbalorditivi. Questi “particolari tipi di segnali” sono impulsi ad alta
energia, come gli applausi di un grande pubblico.

4.3) MPEG-1 Layer III (.mp3)

Come accennato prima, l'MPEG-1 Layer III – più comunemente .mp3 – è un encoder che si serve
del dominio della frequenza, al contrario di come accadeva per l'mp2 e, seppur l'mp3 utilizzi alcune
delle caratteristiche dell'mp2, i due standard sono molto differenti. L'mp3 lavora a 1152 campioni,
ma – come già detto sopra – ha bisogno di prendere molti più dati per l'analisi. In output dà un
numero variabile di campioni, utilizzando un buffer di bit per consentire l'encoding a bitrate
variabile (VBR - variable bitrate) mantenendo una grandezza di output di 1152 campioni.
Questo causa un ritardo significativamente lungo prima dell'output, rendendo l'mp3 inutilizzabile
per le codifiche in tempo reale. L'mp3 non si avvale del filter bank polifase a 32 sotto-bande,
ma utilizza una MDCT (Trasformata Discreta del Coseno modificata) su ogni output per dividere i
dati in 576 componenti di frequenza, processando il tutto nel dominio della frequenza.
Tutto questo consente all'mp3 di avere un modello psico-acustico più preciso e di applicare
attentamente una quantizzazione appropriata ad ogni banda, ottenendo performance molto migliori
rispetto ai precedenti codec a bassi bitrate. Ad ogni modo, utilizzare il dominio della frequenza
comporta qualche limitazione, causando una risoluzione temporale 12 o 36 volte peggiore di quella
dell'mp2. Tutto questo, porta ad artefatti di quantizzazione a causa di suoni di transizione come
eventi ripetitivi ed altri eventi ad alta frequenza che si verificano in un grande range.
Dunque, si possono verificare fenomeni di “pre-eco” o “eco in avanti”, ovvero artefatti di
compressione audio digitale nei quali un suono viene percepito prima che si verifichi
ed è molto evidente negli strumenti a percussione. Grazie ad uno strumento di rilevamento di pre-
eco e l'encoding a bitrate variabile (VBR), l'mp3 è in grado di aumentare temporaneamente il bitrate
nei punti di maggiore difficoltà in modo da attenuare tali difetti.
Oltre al normale “joint stereo” già visto nell'mp2, l'mp3 può utilizzare il “joint stereo” a matrice.
Con il joint stereo a matrice alcuni range di frequenze di entrambi i canali sono uniti in un singolo
canale mono (L+R – Sinistro più Destro), mentre le differenze tra i canali destro e sinistro sono
salvate in un altro canale (L-R – Sinistro meno Destro). A differenza del joint stereo originale
dell'mp2, nel joint stereo a matrice dell'mp3 non c'è alcuna perdita di informazioni;
ad ogni modo, dopo la quantizzazione, gli artefatti generati possono essere molto accentuati.
Se le differenze tra il canale di destra e quello di sinistra sono poche, il secondo canale – quello
delle differenze (L-R – Sinistro meno Destro) – sarà piccolo e questo può comportare fino ad un
massimo di 50% di riduzione del bitrate.
Se, al contrario, le differenze tra i canali destro e sinistro sono tante, è decisamente preferibile
utilizzare il normale encoding stereo, visto che il joint stereo a matrice non comporterebbe alcun
beneficio. Non solo, l'mp3 è anche in grado di passare dalla normale codifica stereo a quella joint
stereo a matrice nello stesso file, il che comporta una ulteriore riduzione di peso.
Un'altra differenza dell'mp3 rispetto all'mp2 è che utilizza la codifica di Huffman a lunghezza
variabile per ridurre ulteriormente il bitrate, senza una ulteriore perdita di qualità.

– Valutazioni finali

Le limitazioni tecniche insite all'mp3 fanno sì che sia impossibile ottenere una qualità audio
cristallina a qualsivoglia bitrate. Questo fa sì che, ad un bitrate sufficientemente alto, l'mp2 risulti
ancora superiore all'mp3, in termini di pura qualità. La popolarità che ha conquistato l'mp3 al
momento del suo debutto è dovuta più che altro al lato consumer che, illo tempore, si concentrava
sulla quantità più che sulla qualità. Per i mezzi dell'epoca, potersi portare dietro nel proprio lettore
USB mp3 una grande quantità di file in uno spazio molto ridotto era vista come una cosa
straordinaria. Seppur ci fossero delle grandi limitazioni nella qualità finale rispetto ai file wav non
compressi estratti dai CD originali, un mp3 a 192 kbit/s veniva – all'epoca – considerato
“accettabile” per l'ascolto di uso comune. Per il nostro test, è stata utilizzata una canzone estratta in
formato lossless wav dal CD originale per una durata totale di 5 minuti e 43 secondi.
Il file non compresso ha un peso di 59,203 MB, è stereo ed ha un campionamento a 44'100 Hz.
Questo file è stato poi encodato in mp3 utilizzando le stesse impostazioni usate all'epoca del suo
utilizzo comune; il risultato è stato un file .mp3 con tecnologia joint stereo a matrice di 192 kbit/s a
44'100 Hz di soli 7,860 MB. È possibile quindi capire come l'mp3 fosse molto utilizzato a suo
tempo per la sua possibilità di compressione. Tornando all'mp2 per un attimo, seppur è vero che a
bitrate sufficientemente alti l'mp2 è migliore in termini di qualità dell'mp3, è anche vero che, a bassi
bitrate, l'mp3 produce artefatti meno significativi rispetto all'mp2.

4.4) Advanced Audio Coding (AAC)

– Introduzione

Col passare degli anni, vennero migliorate anche le varie tecnologie audio e video. Si giunse alla
volta dell'MPEG-2 e venne così deciso di rilasciare un aggiornamento retro-compatibile per l'mp1,
l'mp2 e l'mp3 già introdotti con l'MPEG-1. Ad ogni modo, c'era bisogno di un nuovo codec audio
capace di soddisfare i requisiti sempre più alti per le trasmissioni: cominciarono così i lavori per la
creazione di un nuovo ed innovativo codec non retro-compatibile che si estesero fino all'MPEG-4
Part 10 AVC (Advanced Video Coding) H.264 e dettero vita all'AAC (Advanced Audio Coding).

– Il codec

L'AAC, in linea di massima, segue le stesse caratteristiche indicate per i codec audio precedenti
(filterbank, quantizzazione non uniforme, codifica di Huffman), ma comporta molti miglioramenti
rispetto ai precedenti standard, soprattutto rispetto al suo predecessore e diretto concorrente, l'mp3.
Tra le migliorie più significative rispetto all'mp3 troviamo una risoluzione della frequenza più alta;
parliamo di 1024 contro 576 dell'mp3. Il secondo punto di forza dell'AAC è la predizione.
L'AAC ha la possibilità di effettuare una predizione all'indietro che consente di ottenere una
maggiore efficienza di codifica, soprattutto per i segnali di tono. Il terzo punto di forza dell'AAC è
una versione migliorata del joint stereo. Comparato a quello dell'mp3, le due modalità di codifica
(joint stereo normale ed a matrice) sono molto più flessibili, facendo sì di poter applicare tali
modalità più frequentemente in modo da ridurre il bitrate in modo maggiore.
Il quarto punto di forza dell'AAC, è una codifica di Huffman migliorata.
Ma i vantaggi dell'AAC non comportano solo una compressione audio migliore rispetto ai suoi
predecessori per i normali segnali audio, l'AAC è riuscito a migliorare anche il comportamento nei
segnali più difficili! Una delle tecnologie più interessanti dell'AAC è il “cambio avanzato dei
blocchi”. Invece di utilizzare un filterbank ibrido come quello dell'mp3, l'AAC utilizza un filterbank
con la Trasformata Discreta del Coseno Modificata con un impulso di risposta (per i blocchi più
piccoli) di 5.3 ms ad una frequenza di campionamento di 48 KHz. Comparato all'mp3 – che
raggiunge 18.3 ms – è un ottimo risultato, contando anche il fatto che gli artefatti di pre-eco sono
ridotti in modo notevole. Un'altra tecnologia introdotta dall'AAC è il TNS (Temporal Noise
Shaping) che esegue un riduzione del noise a livello temporale eseguendo una predizione di loop
aperta nel dominio della frequenza. Dai test eseguiti, il TNS si è dimostrato essere particolarmente
utile per il miglioramento della qualità nel parlato a bassi bitrate. Sommando tutte queste piccole
migliorie, l'AAC raggiunge in media la stessa qualità dell'mp3 utilizzando il 70% del bitrate.
Un'altra differenza tra l'AAC e l'mp3 è proprio la frequenza di campionamento, visto che l'AAC è in
grado di supportare frequenze che vanno dagli 8 ai 96 KHz e fino a 48 canali, contro i due canali
supportati dall'mp3 prima dell'aggiornamento ed i 5.1 canali dopo l'aggiornamento effettuato
all'epoca dell'MPEG-2. In altre parole, non solo l'AAC è migliore dell'mp3 a bassi bitrate,
ma può raggiungere codifiche di qualità che l'mp3 non è neanche in grado di processare!
L'approccio che l'AAC ha nei confronti della codifica audio, inoltre, è un approccio “modulare”,
nel senso che è in grado di adattarsi al meglio a tutte le varie situazioni e tipologie di segnali audio
e, per farlo, si serve di vari profili:

1) Main audio profile

Il profilo Main era un profilo molto usato, stabilito ai tempi del primo sviluppo del codec, ovvero
all'epoca dell'MPEG-2, ma è poi diventato obsoleto.

2) Scalable audio profile

Il profilo Scalable venne ideato per avere la necessità di avere un profilo scalabile nel codec.
3) Speech audio profile

Il profilo Speech venne ideato per favorire la codifica di segnali audio prevalentemente parlati.

4) Synthetic audio profile

Il profilo Synthetic altro non è che una “sintesi” del profilo Main.

5) High Quality audio profile

L'High Quality profile venne ideato per concentrarsi sulla qualità, pur comportando un ritardo nella
velocità di codifica; per questo profile l'importante è la qualità finale.

6) Low Delay audio profile

Mentre il profilo precedente era concentrato sulla qualità, questo è concentrato sulla velocità,
ovvero sul basso ritardo e sul cercare di ottenere una codifica il più vicino possibile a quella in
tempo reale.

7) AAC profile

Il profilo AAC è il primo profilo a far parte della seconda fase di sviluppo dell'AAC, quella
dell'MPEG-4 Part 10 AVC H.264. Questo profilo è il profilo più utilizzato nei recenti encoding in
AAC e viene spesso associato come audio di default negli encoding in H.264.

8) High Efficiency AAC profile

L'High Efficiency AAC profile nasce per sfruttare la tecnologia SBR (Spectral Band Replication)
all'interno dell'AAC. Tale profilo non nasce come “sostituto” del profilo AAC, ma come un “sopra-
insieme” che estende le funzionalità dell'AAC, ed i decoder in grado di riprodurre l'HE-AAC sono
in grado di riprodurre anche il profilo AAC. Come detto prima, l'SBR è una tecnica di estensione
della banda che non rimpiazza il core del codec, ma opera in congiunzione ad esso per poter creare
un “sopra-insieme” del codec originale più efficiente, in grado di dimezzare il bitrate richiesto.
Presente in entrambi i processi di encoding e decoding, l'SBR sfrutta al massimo la correlazione tra
le basse e le alte frequenze in un segnale audio per descrivere le alte frequenze di un segnale
utilizzando una piccolissima quantità di dati. Il dato SBR che descrive le alte frequenze è poi
accoppiato ai dati compressi a bassa frequenza del codec AAC. Una volta combinati in fase di
decoding, il bit stream completo HE-AAC contiene tutti i dati per ricreare il segnale delle alte
frequenze (SBR) dal segnale codificato alle basse frequenze dall'AAC.
Il profilo HE-AAC è incluso come profilo nell'AAC e non è un nuovo standard a parte,
proprio perché è retro-compatibile. Difatti, se un file audio encodato in HE-AAC viene mandato ad
un decoder che supporta solo i profili fino a quello AAC, questi sarà comunque in grado di
riprodurre tale file, ma non sarà in grado di combinare il file SBR con quello encodato in AAC e,
di conseguenza, non sarà in grado di ricreare le alte frequenze, ma potrà riprodurre solo le basse
frequenze. Ad esempio, per creare un file stereo con un bitrate di 48 kbit/s col profilo HE-AAC,
l'encoder genera due segnali: un segnale AAC da 42 kbit/s ed un segnale SBR di circa 6kbit/s.
Dunque, i decoder in grado di leggere solo il profilo AAC, leggeranno solo il segnale AAC da 42
kbit/s, mentre quelli in grado di riprodurre l'HE-AAC potranno combinare entrambi i segnali.
Grazie a questa modalità di codifica, l'HE-AAC consente di raggiungere una buona qualità a
bassissimi bitrate, come 128 kbit/s, e tale efficienza di compressione è l'ideale per il file-sharing
e per il futuro digital broadcasting. Ad ogni modo, proprio a causa della sua struttura,
non è utilizzabile per le radiocomunicazioni tra due o più persone quali la telefonia in tempo reale
a causa del suo alto costo computazionale.

9) High Efficiency AAC v2 profile

Come risultato dello sviluppo dell'HE-AAC, è stato rilasciato un ulteriore, nuovo profilo che
comporta delle piccole migliorie rispetto al profilo HE-AAC originale.

Chiudendo la parte relativa ai profili, l'AAC ha anche sviluppato un metodo di correzione degli
errori che viene applicato nei punti nei quali il codec potrebbe essere più soggetto agli errori e non
all'intera traccia audio, in modo da salvaguardare la qualità finale. Inoltre, vengono utilizzati degli
strumenti quali il VCB11 (Virtual Codebook) che individua gli errori all'interno dei dati spettrali
e il RVLC (Reverse Variable Length Code) che riduce la propagazione di errori.

– Valutazioni finali

L'AAC ha segnato una svolta nello sviluppo dei codec di codifica audio ed è in grado di encodare
audio di altissima qualità, con campionamenti altissimi e con un grande numero di canali. Come
codec, raggiunge performance imbattibili sia ad alti bitrate che a bassissimi bitrate ed è stato in
grado di superare i predecessori sotto numerosi aspetti, soprattutto rispetto all'mp3,
suo rivale diretto. Proprio per le sue grandi capacità e per il suo sviluppo che si è protratto per
tempo (dall'MPEG-2 all'MPEG-4 Part 10), l'AAC è stato adottato da numerose compagnie e servizi
e, ad oggi, risulta essere il codec migliore in rapporto qualità-efficienza-supporto.
Giusto per fare alcuni esempi, l'AAC è stato adottato dallo standard di radio digitale DAB+, per gli
standard televisivi DVB-H ed ATSC-M/H, ma anche da numerosi servizi online quali YouTube ed
iTunes ed è supportato nativamente da iPhone, iPad, iPod, NintendoDSi, Nintendo3DS,
PlayStation5, PlayStation4, PlayStation3, PlayStationVita, Nintendo Wii, da Android, dal Black
Berry, da Windows Phone, da numerose autoradio ed altrettanto numerosi televisori.
4.5) AC-3 – Audio Coding 3

Parallelamente allo sviluppo dell'AAC, prese piede una nuova tecnologia, il Dolby Digital Audio e,
con esso, l'AC-3, un codec nato specificatamente per l'audio digitale delle sale cinematografiche e
che prese subito piede. Tale codec trovò inoltre un buon riscontro anche nella televisione digitale
e nei DVD.

– Encoding

L'algoritmo dell'AC-3 raggiunge grandi guadagni in termini di compressione quantizzando la


rappresentazione nel dominio della frequenza del segnale audio. Il primo passaggio nel processo di
encoding è quello di trasformare la rappresentazione dell'audio da una sequenza di campioni
temporali PCM in una sequenza di blocchi di coefficienti di frequenza e questo viene fatto tramite il
filterbank. I blocchi di overlap di 512 campioni di tempo sono moltiplicati da una finestra di tempo
e trasformati nel dominio della frequenza. A causa dei blocchi di overlap, ogni campione PCM in
input è rappresentato in due blocchi trasformati sequenziali.
La rappresentazione nel dominio della frequenza può poi essere decimata da un fattore di due,
in modo che ogni blocco contenga 256 coefficienti di frequenza.
I coefficienti di frequenza individuali sono rappresentati in notazione binaria esponenziale come un
esponente binario ed una mantissa. Il set di esponenti è encodato in una rappresentazione
approssimata dello spettro del segnale che viene chiamato “involucro spettrale”. Questo “involucro
spettrale” è utilizzato dal processo di allocazione di bit che determina quanti bit usare per encodare
ogni mantissa individuale. L'involucro spettrale e le varie mantissa quantizzate per 6 blocchi audio
(1536 campioni audio per canale) sono formattati in un dato di sync AC-3
ed il bitstream AC-3 altro non è che una sequenza di dati di sync AC-3.

A dire la verità, il processo di encoding audio effettuato dall'AC-3 è più complesso di quello
descritto sopra e le seguenti parti non sono state incluse nella spiegazione riportata sopra:

1) Viene incluso un dato header che contiene varie informazioni quali il bitrate, il
campionamento, il numero di canali encodati ed altre informazioni richieste per decodificare
il bitstream encodato.
2) Vengono inseriti dei codici di rilevamento degli errori in modo da consentire al decoder di
verificare se un determinato dato di sync AC-3 è corrotto o meno.

3) La risoluzione spettrale del filterbank di analisi può essere alterata dinamicamente in modo
da adattarsi al meglio alle caratteristiche tempo-frequenza di ogni blocco audio.

4) L'involucro spettrale può essere encodato con risoluzioni tempo-frequenza variabili.

5) Può essere effettuata un'allocazione di bit più complessa ed i parametri del processo di
allocazione dei bit possono essere modificati in modo da produrre un'allocazione migliore.

6) I canali possono essere accoppiati assieme alle alte frequenze in modo da raggiungere un
migliore guadagno di codifica per operazioni a bassi bitrate.

7) Nella modalità a due canali può essere effettuato un processo re-matrizzazione in modo da
raggiungere maggiori performance di codifica ed ottenere risultati migliori nel caso in cui un
segnale a due canali venga decodificato con un decoder a matrice surround.

– Decoding

Il processo è praticamente l'inverso del processo di encoding. Il decoder deve ordinare il bitstream
encodato, controllare che sia privo di errori e de-formattare i vari tipi di dati quali l'involucro
spettrale encodato e le mantissa quantizzate. Il processo di allocazione dei bit viene inizializzato ed
i risultati sono utilizzati per scompattare e de-quantizzare le mantissa. L'involucro spettrale è
decodificato per produrre gli esponenti, dopodiché, gli esponenti e le mantissa sono trasformati
di nuovo nel dominio del tempo per produrre i campioni PCM di tempo decodificati.

In realtà, esattamente come per il processo di encoding, anche il processo di decoding è più
complesso di quello descritto di sopra e sono stati esclusi i seguenti passaggi:

1) Può essere applicata la correzione degli errori se questi vengono individuati.


2) I canali che hanno i contenuti ad alta frequenza accoppiati devono essere disaccoppiati.

3) Il processo di de-matrizzazione deve essere applicato (nella modalità due canali) ogni volta
che i canali sono stati re-matrizzati.

4) La risoluzione del filterbank di sintesi deve essere dinamicamente alterata nello stesso modo
usato dall'encoder nel filterbank di analisi durante il processo di encoding.

– Valutazioni finali

L'AC-3 è un codec in grado di encodare una source con un massimo di 6 canali in un bitrate che
varia da 32kbps a 640kbps. Quando tutti i sei canali sono presenti, la composizione audio viene
detta 5.1. Lo 0.1 si riferisce infatti al canale a banda frazionaria pensato appositamente per i segnali
delle basse frequenze (subwoofer). L'utilizzo dell'AC-3 è molto ampio e tale codec è utilizzato
soprattutto negli standard di televisione digitale e per i DVD grazie alla sua struttura che lo rende un
codec affidabile e capace di poter codificare segnali a qualità molto alta.

– AC-3 vs AAC

Un interessante confronto è quello tra AC-3 ed AAC; sebbene i due codec nascano con intenti
diversi, entrambi sono in grado di codificare segnali audio non compressi in maniera ottimale dal
punto di vista della qualità percettiva finale. Ad ogni modo, proprio per il loro scopo di utilizzo
finale, l'AC-3 risulta essere leggermente inferiore all'AAC per quanto riguarda la compressione di
segnali audio ad altissima qualità dal mero punto di vista del peso finale e l'AAC si rivela infatti
essere superiore dal punto di vista della compressibilità. Nel test effettuato ho deciso quindi di
utilizzare un file stereo wav lossless a 44.1 KHz, 1411kbps da 1 minuto e 29 secondi per un peso
complessivo di 15.1 MB. Per l'encoding è stato scelto un bitrate di 384 kbps per entrambi i codec
audio AC-3 ed AAC. Entrambi sono stati encodati utilizzando il comando -vbr (Variable Bitrate) in
ffmpeg, tuttavia il codec AC-3 ha ignorato tale comando producendo un file a bitrate costante di
384 kbps, mentre l'AAC ha prodotto un file a bitrate variabile il cui bitrate oscilla tra i 254 kbps ed i
432 kbps, con una media di 384 kbps. Il peso finale dei file è di 4.11 MB per l'AC-3 e 4.01 MB per
l'AAC che, come dicevo, risulta essere migliore in termini di compressione (rapporto qualità/peso).
Grazie al bitrate variabile l'AAC è riuscito a salvare spazio nei punti meno importanti della
sequenza audio ed ha sfruttato tale bitrate risparmiato per coprire i punti di maggiore richiesta in
termini di bitrate; così facendo il risultato finale è senza dubbio impeccabile e migliore rispetto a
quello – sempre comunque ottimale – dell'AC-3.

4.6) Vorbis (.ogg)

Un altro interessante codec audio è il Vorbis .ogg che nacque come codec totalmente libero e senza
licenze. Al tempo della creazione del codec, il suo rivale diretto era l'mp3 e – proprio per questo –
venne ideato in modo da esservi superiore. Ad ogni modo, tale codec è stato aggiornato per molto
tempo e si è scontrato anche contro l'AAC, non riuscendo però ad ottenere i risultati sperati.
Seppur la sua compatibilità sia molto inferiore rispetto a quella dall'AAC ed i risultati ottenuti nei
test siano stati inferiori a quest'ultimo (ma pur sempre superiori all'mp3),
ho deciso di riservargli un piccolo spazio in questa tesi.
– Il codec (encoding e decoding)

Il vorbis riesce ad encodare master audio da 8 KHz a 192 KHz e varie rappresentazioni di canali
quali quella stereo, la 5.1 ed addirittura fino a 255 canali discreti. Prendendo come source un audio
wav non compresso di un CD a 44.1 KHz, il vorbis è in grado di produrre un file di output da 45 a
500 kbit/s, a seconda della qualità. Questa viene impostata secondo i parametri -q, ovvero: -q-1
(45kbit/s), -q0 (64kbit/s), -q1 (80kbit/s), -q2 (96kbit/s), -q3 (112kbit/s), -q4 (128kbit/s), -q5
(160kbit/s), -q6 (192kbit/s), -q7 (224kbit/s), -q8 (256kbit/s), -q9 (320kbit/s), -q10 (500kbit/s).
Chiaramente, questi bitrate sono indicativi in quanto il vorbis utilizza – esattamente come l'AAC –
il VBR (bitrate variabile) per massimizzare l'efficienza di compressione. Sotto l'aspetto tecnico, il
vorbis è basato sulla Trasformata Discreta del Coseno Modificata e la utilizza per convertire i dati
sonori dal dominio del tempo a quello della frequenza. Il dato risultante del dominio della frequenza
è poi diviso in piano di noise (ovvero la misura del segnale creata dalla somma di tutte le fonti di
noise ed i segnali non voluti, con qualsiasi altro segnale oltre a quello tenuto in considerazione) ed i
componenti residui, per poi essere quantizzato ed encodato entropicamente utilizzando un algoritmo
di quantizzazione vettoriale basato sulle parole di codice. Per quanto riguarda il processo di
decoding, invece, altro non è che il processo inverso dell'encoding.

– AAC vs Vorbis

Seppur il vorbis risulti essere superiore all'mp3 in termini di qualità, è senza dubbio inferiore
all'AAC sia in termini di compressione che, soprattutto, in termini di supporto. Mentre l'AAC è un
codec supportato da praticamente ogni piattaforma, il vorbis non lo è e questo ha frenato
ulteriormente il suo impiego. Per quanto riguarda i bassi bitrate, il vorbis ha un approccio singolare
con quest'ultimi e, invece dei soliti artefatti da compressione, vengono percepiti dei suoni simili ad
un riverbero in un grande anfiteatro. Questo genere singolare di artefatti è dato proprio
dall'approccio che ha scelto il vorbis come codec audio, ovvero quello del piano di noise.
Per quanto riguarda invece il problema di pre-eco già affrontato per gli altri codec, il vorbis non ne
è esente, tuttavia cerca di eliminarlo utilizzando una funzione automatica interna di “tune” che si
attiva per i bassi bitrate, cercando di ridurne l'effetto. Sebbene i suoi risultati siano stati inferiori a
quelli dell'AAC (soprattutto quando l'AAC utilizza il profilo HE ed HE v2), molte compagnie
hanno deciso di utilizzare il vorbis proprio per il fatto che è open source.
Tra i nomi più famosi spiccano compagnie come Spotify, Wikipedia ed anche giochi come
Grand Theft Auto: San Andreas, Halo: Combat Evolved, World of Warcraft e persino Minecraft.

4.7) Opus (.opus)

Per quanto riguarda il campo delle radiocomunicazioni in tempo reale, spicca il nome del codec
Opus .opus; un codec che nasce con un unico principale intento: la bassa latenza. Come è stato
possibile appurare nel corso della tesi, però, in genere per ottenere una bassa latenza è necessario
avere una bassa complessità e, dunque, un basso costo computazionale che non è sintomo di buona
efficienza in caso di compressione. Per arginare il problema, l'opus si serve della codifica predittiva
lineare (algoritmo SILK originariamente inventato ed utilizzato da Skype) e della Trasformata
Discreta del Coseno Modificata, passando da un metodo all'altro;
il bitrate, la banda audio, la complessità e l'algoritmo possono essere modificati tutti in tempo reale.
– Il codec

L'opus supporta bitrate costanti e variabili che vanno da 6 kbit/s a 510 kbit/s, con campionamenti
che vanno dagli 8 KHz (con 4 KHz di banda) a 48 KHz (con 20 KHz di banda),
ovvero che comprendono il raggio uditivo umano.
L'opus supporta fino a 255 canali audio e consente l'accoppiamento dei canali tra gruppi di canali di
due. In ogni stream opus, il bitrate, la banda e la latenza cambiano continuamente senza introdurre
alcuna distorsione o discontinuità; persino mischiando pacchetti di stream diversi
si verifica un regolare cambiamento invece di una distorsione!
Non solo, a differenza del vorbis, l'opus non ha bisogno di lunghe parole di codice per ogni singolo
file, rendendolo più efficiente per piccole clip audio. Per quanto riguarda il lato tecnico, l'opus è
basato su una combinazione di CELT (Constrained Energy Lapped Transform) e SILK, entrambi
estremamente modificati: il CELT è basato sulla Trasformata Discreta del Coseno Modificata,
utilizzando la CELP (Code-excited linear prediction) per una migliore predizione, mentre il SILK è
basato sulla codifica predittiva lineare. Nella loro implementazione nel codec Opus, entrambe sono
state modificate per ottenere ulteriori miglioramenti algoritmici, nonché per poter supportare range
più vasti. Inoltre, il CELT include sia la replicazione spettrale che la generazione del noise (simile
all'SBR dell'AAC) ed è in grado di salvare ulteriormente bit filtrando i suoni armonici e facendoli
replicare dal decoder in fase di decoding.

– I preset (mode)

L'opus ha tre preset chiamati “mode”, ovvero:

1) Speech mode, che utilizza il SILK puro, consentendo basse latenze e bitrate per le
conversazioni audio.

2) Hybrid mode, che utilizza il SILK puro fino a 8 KHz, per poi passare al CELT per raggi di
frequenze superiori agli 8 Khz.

3) CELT, che utilizza il CELT puro, pensato principalmente per la codifica audio generica.

Mentre il SILK è esclusivamente VBR (bitrate variabile) e non può raggiungere un determinato
bitrate, il CELT è in grado di utilizzare il CBR (bitrate costante) e viene automaticamente attivato
nei casi in cui questo viene richiesto.

– Opus VS AAC

Concettualmente, i due codec nascono per scopi molto diversi ed hanno difatti ottenuto risultati
molto diversi nei vari test. L'opus, con la sua bassa latenza, nasce per le conversazioni audio in
tempo reale e per gli eventi live e risulta essere molto superiore all'AAC per bitrate come 64 kbit/s.
Ad ogni modo, per quanto riguarda la qualità finale di un prodotto professionale quale l'audio di un
film in Dolby 5.1, ma anche di una semplice serie televisiva in stereo, l'AAC risulta essere migliore
per due motivi fondamentali: in primo luogo, il vantaggio in termini di compressione dell'opus va
scemando all'aumentare del bitrate e secondariamente poi, l'AAC – al contrario dell'opus –
è largamente supportato come standard, rendendo il piccolissimo e talvolta quasi nullo
(se non totalmente nullo) vantaggio in termini di compressione ad alti bitrate assolutamente non
sufficiente a giustificare il suo utilizzo in tal campo.
4.8) I codec audio lossless: FLAC e WAV a confronto

Così come accadeva per la codifica delle immagini fisse e quella delle immagini in movimento,
è possibile codificare segnali audio in modo lossless. Mentre per le immagini fisse risulta ancora
conveniente adottare una codifica lossless a causa dell'ottima rappresentazione visiva e delle
dimensioni comunque ridotte (PNG), non si può certo dire lo stesso per i video che, in modalità
lossless, risultano essere di circa 50 GB (AVI lossless senza compressione) o 22 GB (H.264 con
compressione lossless) per un video di 24 minuti in 1280x720 da 23,976 fps, progressivo.
Certamente, seppur rispetto ad una codifica lossless senza compressione ci sono stati miglioramenti,
un divario di 22 GB H.264 lossless contro i 550 MB H.264 lossy High 10bit, preset placebo, crf 14
per un video da 24 minuti di qualità ottima è troppo vasto. Dunque, tutto ciò è conveniente per le
immagini ed impraticabile per i video, ma, per quanto riguarda la codifica audio, si ha una via di
mezzo. Come mostrato dai precedenti test, una canzone di durata media da 1 minuto e 14 a 44.1,
1411 kbps stereo da 15.1 MB può essere compressa in 4.01 MB AAC lossy da 384 kbps VBR o in
4.11 MB AC3 lossy da 384 kbps CBR; ad ogni modo, ciò potrebbe non tornare comodo nel mercato
consumer quando si hanno canzoni lossless da 4 minuti ed oltre che raggiungono la soglia di 50
MB. In questo senso, viene in aiuto il FLAC, un codec audio lossless che consente di avere una
compressione migliore rispetto al WAV e che, senza dubbio, può tornare utile in innumerevoli casi.

– WAV (Waveform Audio File Format)

Il WAV è uno standard ideato agli albori dei computer da Microsoft ed IBM per poter portare i
bitstream audio proprio sui computer ed è molto simile (se non quasi identico) all'AIFF ideato per il
MAC. Il WAV è stato costantemente aggiornato fino al 2007, anno in cui è stata effettuata l'ultima
release. L'audio contenuto nel WAV è audio non compresso nel formato LPCM (Linear Pulse Core
Modulation), ovvero lo standard dei CD, che hanno due canali (stereo) LPCM con campionamento
a 44.1 KHz. Sebbene il WAV non sia molto utilizzato dal lato consumer e sia stato utilizzato in
passato prevalentemente per avere una copia identica del CD acquistato da poter riprodurre sui
computer, questo è tutt'ora molto utilizzato nel lato professionale. Negli studi, difatti, è talvolta
necessario avere un file stereo lossless non compresso da poter lavorare, modificare e preparare per
la messa in onda. Le emittenti radio più famose che utilizzano il WAV per i file audio non compressi
nei vari passaggi di lavorazione interna (dallo studio di registrazione al playout) sono la BBC,
Global Radio UK e la ABC. Ad ogni modo, al momento della creazione del WAV – agli albori dei
computer – venne scelto di utilizzare un intero a 32bit per registrare il file size nell'header e dunque
un file audio singolo WAV non può essere più grande di 4GB ed alcuni lettori sono limitati a 2GB.
Mentre per la qualità CD di 44.1 KHz stereo a 1411 kbps CBR (bitrate costante) non compresso un
limite di 4GB può sembrare un'enormità (circa 7 ore), tale limite è facilmente oltrepassabile quando
si aumenta il campionamento e si hanno più canali e non più la codifica stereo.
Per tale motivo, è stata rilasciata una nuova versione del WAV chiamata WAV64 che utilizza un
header a 64bit. Tale scelta è stata d'obbligo, soprattutto se si pensa alle capacità del WAV che può
vantare un campionamento che va da 1 Hz a 4.3 GHz ed un numero di canali che va dal mono,
allo stereo ad aumentare fino a 65535!

– WAV ed il CD-DA (Compact Disk Digital Audio)

Molto spesso, nel lato consumer, vengono creati CD per autoradio od altro partendo dal WAV,
anche se il formato dei CD è il CD-DA. Questo è possibile in quanto sia il CD-DA che il WAV
contengono l'audio in PCM. Il WAV, difatti, è nato proprio come formato audio per computer
e non può essere riconosciuto dai CD in modo diretto.
Per poter inserire un file WAV su un CD in modo che questo possa essere riprodotto secondo gli
standard dei lettori CD, questo dev'essere privato dell'header ed i dati audio PCM devono essere
scritti direttamente sul CD secondo lo standard con un campionamento a 44.1 KHz.

– FLAC (Free Lossless Audio Codec)

Il FLAC è un codec audio che nasce dall'esigenza di avere una codifica audio lossless con
compressione e non più priva di compressione come accadeva con il WAV. Il FLAC supporta
campionamenti da 1 a 655350 Hz e da 1 ad 8 canali. I canali, inoltre, possono essere accoppiati
(come nel caso dei canali stereo o della composizione 5.1) per sfruttare la loro correlazione
ed aumentare la compressione. Il funzionamento del FLAC è molto semplice: questo codec utilizza
la predizione lineare per convertire i dati audio; tale predizione può essere di quattro tipi quali
“zero”, “verbatim”, “fixed linear” e “FIR linear”. Per poter comprimere i file, è possibile scegliere 8
livelli di compressione (tutti lossless, ovviamente) che vanno da 0 (fastest) ad 8 (smallest) e
cambiano precisione ed approccio. Una volta completato il calcolo di predizione secondo il
parametro di compressione richiesto (da 0 ad 8), vengono calcolate le differenze tra la predizione
ed il dato calcolato ed il risultato ottenuto da questo calcolo viene chiamato “residuo”.
Il “residuo” viene poi salvato utilizzando la codifica lossless di Golomb-Rice.

– Il cuore del FLAC: la codifica di Golomb-Rice

La codifica di Golomb utilizza un parametro M per dividere il valore in input in due parti, quali “q”
(ovvero il risultato della divisione per M) ed “r” (il resto). Il quoziente è inviato in codifica unaria
(encoding entropico che rappresenta un numero naturale n con n-uno seguiti da uno zero se il
numero naturale è intero e non negativo, ed n meno 1 uno se il numero naturale è intero e positivo)
seguita dal resto in encoding binario troncato.
Quando M è uguale ad 1, la codifica di Golomb è equivalente a quella unaria:

I codici di Golomb-Rice possono essere pensati come codici che indicano un numero per la
posizione di q e dell'offset con r. La figura soprastante mostra infatti la posizione di q e dell'offset r
per l'encoding di N interi utilizzando il parametro di Golomb-Rice M.
Formalmente, le due parti sono date dalla seguente espressione, dove x è il numero da encodare:

ed r = x -qM -1. Il risultato finale assomiglia a (q + 1) r.


Da notare che r può essere di un numero variabile di bit; nello specifico è b bit nella codifica Rice,
e cambia da b-1 a b bit per la codifica di Golomb (ovvero M non è una potenza di 2).
Supponiamo che:

Se:

allora vengono utilizzati b-1 bit per encodare r; ma se:


allora vengono utilizzati b bit per encodare r. Chiaramente,

se M è una potenza di 2 e possiamo encodare tutti i valori di r con b bit.


Il parametro M è una funzione del corrispondente processo di Bernoulli, che è parametrizzato da:

la probabilità di successo in un dato tentativo di Bernoulli.


M è anche la media della distribuzione o la media +/- 1 e può essere determinata
da queste disuguaglianze:

Golomb dice che, per un largo M, c'è una piccolissima “penalizzazione” nel prendere:

Il codice di Golomb per questa distribuzione è equivalente al codice di Huffman per le stesse
probabilità, se fosse possibile computare il codice di Huffman.
Lo schema di Golomb era designato per encodare sequenze di numeri non negativi, tuttavia è
facilmente esteso per accettare sequenze contenenti numeri negativi utilizzando uno schema di
“overlap ed interleave”, nel quale tutti i valori sono riassegnati ad alcuni numeri positivi in modo
unico ed irreversibile. La sequenza comincia con 0, -1, 1, -2, 2, -3, 3, -4, 4 ecc. L'n-esimo valore
negativo (ovvero -n) è mappato all'n-esimo valore dispari (2n-1) e l'm-esimo valore positivo è
mappato all'm-esimo valore pari (2m). Questo può essere matematicamente espresso come segue:
un valore positivo x è mappato a

ed un valore negativo y è mappato a:

Questo è un codice prefisso ottimale solo se sia il positivo che la magnitudine dei valori negativi
seguono una distribuzione geometrica con lo stesso parametro.
Il FLAC utilizza anche il run-length encoding: dato un alfabeto di due simboli, o un set di due
eventi, P e Q, con probabilità rispettivamente di p e (1-p), dove p è maggiore o uguale ad ½, la
codifica di Golomb può essere utilizzata per encodare “run” di zero o più Ps separati da un singolo
Q's. In questa applicazione la miglior impostazione per il parametro M è l'intero più vicino a:

Dove p = ½, M = 1 ed il codice di Golomb corrisponde all'unario (n maggiore o uguale a 0 P's,


seguito da un Q encodato come n uno seguiti da zero).

– Valutazioni finali sul FLAC

Come visto ed analizzato in precedenza, il FLAC utilizza un metodo di codifica lossless che,
a differenza del WAV, utilizza un particolare metodo di compressione.
A differenza degli altri algoritmi di compressione lossless come il DEFLATE utilizzato nella
compressione zip, il FLAC, in quanto codec audio, comprime servendosi delle caratteristiche audio
ed i produttori attestano che è in grado di raggiunge risultati molto più efficienti rispetto alla
codifica usata dallo zip. Un file FLAC, inoltre, è pronto per la decodifica in maniera immediata,
mentre un file zip deve essere estratto e poi riprodotto. Ad ogni modo, il FLAC, a differenza del
WAV, ha un'adozione minima proprio per il suo supporto che è molto limitato.
Nel test effettuato, è stato preso un file master originale da 3 minuti e 52 secondi a 44.1 KHz PCM.
Il processore utilizzato per effettuare questo test è un Intel Atom N450 monocore, dual thread
con 512 kb di cache l2 (privo di cache l3) e 1.62 GHz con moltiplicatore statico a x10
(1662.7 MHz). Il file WAV 44.1 Khz 1411 kbps è stato salvato in circa 4 secondi ed ha una
dimensione di 39.1 MB. Il file .rar salvato con modalità di compressione migliore è stato invece
creato in 25 secondi ed ha un peso sostanzialmente minore del file WAV non compresso, di 30.8
MB. È venuto poi il turno dei file FLAC che – per la modalità di compressione migliore – ha
impiegato ben 9 minuti e 47 secondi per encodare tale file con risultati discutibili, tra l'altro.
Il file finale è un VBR da 31.4 MB, senz'altro migliore rispetto ai 39.1 MB del file WAV non
compresso, ma comunque inferiore rispetto ai 30.8 MB del file .rar. C'è da dire che,
mentre il file rar deve essere estratto per essere riprodotto, il file FLAC no,
e 600 KB non sono di certo un grande vantaggio da parte del file .rar, però, di certo,
l'alto costo computazionale in encoding di 9 minuti e 47 secondi – soprattutto se si utilizza una
macchina poco potente – non è da sottovalutare.
Come ultima riprova finale del fatto di essere lossless, ho deciso di mettere a confronto le due tracce
audio WAV non compressa e FLAC, analizzandone la forma:
- Valutazioni Finali della Tesi -
Con questo si conclude il percorso della tesi che ha visto il suo evolversi in 4 punti fondamentali:
le trasformate, il loro utilizzo nella codifica delle immagini fisse, nella codifica di quelle in
movimento e nella codifica dei segnali audio. Alla fine di questo percorso, è stato possibile appurare
come la trasformata di Karhunen-Loève sia la miglior trasformata possibile in termini di
compressione, ma questa sua peculiarità sia vanificata dal fatto che utilizza delle funzioni di base
dipendenti dal dato di ingresso, il che comporta la continua computazione della matrice di
covarianza del segnale in ingresso, così come la sua memorizzazione e la trasmissione.
Il suo utilizzo nell'HEVC si è dimostrato inutile ed infatti non è stata implementata nello standard
finale, così come non è stata implementata nell'H.266. La DCT infatti si è dimostrata essere
un'ottima trasformata e le sue caratteristiche quali utilizzare solo numeri reali ed il fatto di essere
periodica in 2N hanno sancito la sua vittoria contro la trasformata di Fourier che utilizza invece
numeri complessi ed è periodica in N, introducendo discontinuità più grandi. La trasformata di
Walsh-Hadamard utilizza invece matrici puramente reali ed il suo impiego ha un bassissimo costo
computazionale, tuttavia, anche la sua capacità di compressione è altrettanto modesta. Durante la
tesi è stato poi inoltre possibile vedere come la trasformata Discreta di Wavelet sia tornata utile nel
tentare un altro approccio nella codifica delle immagini fisse, quella del JPEG2000, con la
trasformata non più applicata a blocchi, per ottenere un'immagine esente da blocking, a differenza
del JPEG normale. Durante la tesi è stato poi possibile appurare come, per la codifica delle
immagini fisse, sia possibile ottenere dei buoni rapporti di compressione in modalità lossless (come
nel caso del PNG) e come questo non sia possibile per la codifica delle immagini in movimento,
con la codifica audio a metà strada con lo standard FLAC lossless che non porta però compressioni
ottimali ed il cui supporto è ancora limitato ad un numero ridotto di device. La tesi ha inoltre
illustrato l'evoluzione dei vari standard di codifica video e l'implementazione di una versione
modificata dell'H.264 che poi ha dimostrato come l'utilizzo di una trasformata diversa, quella di
Karhunen-Loève, non avrebbe portato benefici sostanziali ma avrebbe comportato un aumento del
costo computazionale notevole e per questo non è stata utilizzata nello sviluppo dell'H.265 HEVC e
dell'H.266 VVC. Durante la tesi è stato infine possibile vedere come alcuni approcci abbiano aperto
le strade allo sviluppo di nuovi codec, mentre altri si siano rivelati inefficaci e siano stati poi
abbandonati negli standard successivi. In definitiva, da sempre si è cercato di comprimere i segnali
inviati, siano questi video o audio, nei più diversi modi ed utilizzando le più disparate tecnologie;
sono stati ideati diversi metodi che utilizzano vari tipi di trasformata e, addirittura, più di una
trasformata, cercando di tenere in conto il rapporto tra compressione, qualità e costo
computazionale. Alcune soluzioni hanno segnato un inizio, altre sono state sorpassate ed altre
ancora non hanno funzionato fin dai loro albori, ma ognuna di esse, ognuno di questi approcci è
servito ai ricercatori per sviluppare al meglio i modelli susseguenti e, così come i ricercatori del
passato hanno usufruito delle tecnologie e degli errori dei loro predecessori, anch'io spero che le
ricerche svolte in questo documento possano servire agli sviluppatori del domani che volgeranno lo
sguardo al passato per migliorare le tecnologie del futuro.

Francesco Bucciantini
Broadcast Encoder
Bibliografia
– W.J Choi, S.Y Jeon, C.B Ahn, S.J Oh “A multi-dimensional transform for future video
coding”, the 23rd international technical conference on circuits/systems
– B.Furht, K.Gustafson, H. Huang, O. Marques, “An adaptive three-dimensional DCT
compression based on motion analysis”, proceedings of the ACM symposium on applied
computing
– B.Zeng, J.Fu “Directional discrete cosine transform – a new framework for image coding”
IEEE transactions on circuits and systems for video technology
– S.Ma C.Kuo “High-definition video coding with super-macroblocks”, proceeding SPIE
visual communications and image processing
– J.Dong, K.N. Ngan, C.K. Fong, W.K Cham, “2-D order 16 integer transforms for HD video
coding” IEEE transactions on circuits and systems for video technology
– N. Kamaci, Y. Altunbasak “Performance comparison of the emerging H.264 video coding
standard”, IEEE International conference on Multimedia and Expo
– M.H Pinson, S.Wolf, G.Cermak, “HDTV Subjective quality of H.264 vs MPEG-2, with and
without packet loss”, IEEE Transactions on broadcasting
– T.Wiegard, G.J Sullivan, G.Bjontegaard, A. Luthra, “Overview of the H.264/AVC Video
Coding standard”, IEEE transactions on circuits and systems for video technology
– K.Panusopone, A. Luthra, “Performance comparison of MPEG-4 and H.263+ for streaming
video applications”, circuits systems signal processing
– F. Pereira, T. Ebrahimi, Eds, “The MPEG-4 book”
– B. Girod, E. Steinbach, N.Farber, “Comparison of H.263 and H.261 video standards”,
standard and common interfaces for video information systems
– Brogent Techologies Inc, Video compression
– ITU-T, Reccomendation, H.263
– L.Maki, Video compression standards
– S.Liu, “Performance comparison of MPEG-1 and MPEG-2 video standards”, IEEE
Proceedings of COMPCON
– T.Von Roden, “H.261 and MPEG-1 – A comparison”, Conference proceedings, IEEE annual
international phoenix conference of computer communications
– F.Pereira, Digital video storage
– M.Handley, H.261
– M.Liou “Overview of the px64kbit/s video coding standard”, communications of the ACM
– Athanassios Skodras, Charilaos Christopulos, Touradj Ebrahimi, “The JPEG 2000 Still
image compression standard”, IEEE Signal processing magazine
– M.W Marcellin, M.J Gormish, A. Bilgin, M.P Boliek, “An overview of JPEG 2000”, IEEE
Data compression conference
– ITU-T, Reccomendation T.81
– G.Bjontegaard “Calculation of the average PSNR Differences between RD-Curves”, VCEG-
Meeting
– JCT-VC “Common test conditions and software reference configurations” JCTV-B300,
meeting, Switzerland
– F. Pereira, Digital Image Compression
– Math-works: eigenvalues and eigenvectors function
– Math-works: Reshape function
– Math-works: Cosine function
– Math-works: Sine function
– Math-works: Discrete Cosine Transform matrix
– Math-works product: MATLAB
– W.H Chen, C. Smith, S. Fralick, “A fast computational algorithm for the Discrete Cosine
Transform”, IEEE Transactions on communications
– M. Naccari, Recent advances on High Efficiency Video Coding (HEVC)
– M. Naccari, F. Pereira “Integrating a spatial just noticeable distortion model in the under
development HEVC codec”, International conference on acoustics, speech and signal
processing, Czech Republic
– JCT-VC “Suggestion for a Test Model”, JCTV meeting, Germany
– JCT-VC “Draft call for proposal on High Performance Video Coding (HVC)”, Japan
– M.Lobato, D.F.P. Capelo, “Advances on transforms for High Efficiency Video Coding”
– BBC UK: HEVC software coordination
– Iphome Deustchland: H.264/AVC software coordination
– M.R Pickering, Optimum basis function estimation for inter-frame perdiction errors
– F. Pereira: advanced multimedia coding
– P. Waldemar, S.O Aase, J.H. Husoy, “A critique of SVD-based image coding systems”,
proceeding of the IEEE international symposium on circuits and systems, Florida, USA
– M. Biswas, M. R. Pickering, M.R Frater, “Improved H.264 based video coding using an
adaptive transform”, proceeding of IEEE international conference on image processing,
Hong Kong
– R. Westwater, B. Furht, “Real time video compression – techniques and algorithms”,
Norwell, USA
– A. N Netravali, B. G Haskell, “Digital pictures: representation, compression and standards”,
New York, USA
– G. R Pehrson, T. Boutell, A. M. Costello, T. Lane, “PNG (Portable Network Graphics)
Specification”
– H. Autti, J. Bistrom “Mobile audio, from mp3 to AAC and further”
– D. Y. Pan, “Digital audio compression”
– Hari, “Compression algorithms: Huffman and Lempel-Ziv-Welch (LZW)”
– Wang, Zhou; Bovik, A.C.; Sheikh, H.R.; Simoncelli, "Image quality assessment: from error
visibility to structural similarity"
– Y.-W. Huang, C.-W. Hsu, C.-Y. Chen et al., “A VVC proposal with quaternary tree plus
binary-ternary tree coding block structure and advanced coding techniques”
– B. Bross, J. Chen, S. Liu, and Y.-K. Wang “Versatile Video Coding (Draft 8)” JVET-Q2001
– F. Bossen, J. Boyce, X. Li, and V. Seregin, K. Sühring, “JVET common test conditions and
software reference configurations” JVET-N1010
– P. Hanhart, J. Boyce, and K. Choi, “JVET common test conditions and evaluation
procedures for 360° video” JVET-K1012

Potrebbero piacerti anche