+923
@@ -0,0 +1,923 @@
|
||||
[](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)
|
||||
|
||||
# Introduzione
|
||||
|
||||
Una introduzione alla tecnologia del video digitale, destinata prevalentemente a ingegneri o sviluppatori software, ma sufficientemente **semplice per consentire a chiunque di imparare**. L'idea è nata durante un [workshop sulla tecnologia video per principianti](https://docs.google.com/presentation/d/17Z31kEkl_NGJ0M66reqr9_uTG6tI5EDDVXpdPKVuIrs/edit#slide=id.p).
|
||||
|
||||
L'obiettivo è introdurre alcuni importanti concetti sul video digitale, usando un **vocabolario semplice, molte figure e esempi pratici** quando possibile, e rendere questa conoscenza disponibile ovunque. Non esitare a inviare correzioni o suggerimenti!
|
||||
|
||||
Ci saranno delle sezioni con esempi e esercizi che richiedono di avere Docker installato e una copia di questa repository scaricata in locale.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/leandromoreira/digital_video_introduction.git
|
||||
cd digital_video_introduction
|
||||
./setup.sh
|
||||
```
|
||||
> **ATTENZIONE**: quando vedi scritto un comando come `./s/ffmpeg` oppure `./s/mediainfo`, significa che si sta eseguendo quel programma all'interno di un container Docker, che contiene tutte le dipendenze richieste per funzionare.
|
||||
|
||||
**Tutti gli esempi pratici devono essere eseguiti dalla repository locale che hai scaricato**. Per gli esempi di jupyter, devi avviare il server eseguendo `./s/start_jupyter.sh`, e aprire in un browser l'URL mostrato.
|
||||
|
||||
# Indice
|
||||
|
||||
- [Introduzione](#introduzione)
|
||||
- [Indice](#indice)
|
||||
- [Terminologia base](#terminologia-di-base)
|
||||
* [Altri modi per codificare un'immagine a colori](#altri-modi-per-codificare-unimmagine-a-colori)
|
||||
* [Esercizio: sperimentare con le immagini e i colori](#esercizio-sperimentare-con-le-immagini-e-i-colori)
|
||||
* [I DVD hanno un DAR 4:3](#i-dvd-hanno-un-dar-43)
|
||||
* [Esercizio: controllare le proprietà di un file video](#esercizio-controllare-le-propriet%C3%A0-di-un-file-video)
|
||||
- [Rimozione delle informazioni ridondanti](#rimozione-delle-informazioni-ridondanti)
|
||||
* [I colori, la luminanza e i nostri occhi](#i-colori-la-luminanza-e-i-nostri-occhi)
|
||||
+ [Modelli di colore](#modelli-di-colore)
|
||||
+ [Conversione tra YCbCr e RGB](#conversione-tra-ycbcr-e-rgb)
|
||||
+ [Sottocampionamento della crominanza](#sottocampionamento-della-crominanza)
|
||||
+ [Esercizio: vedere l'istogramma YCbCr](#esercizio-vedere-listogramma-ycbcr)
|
||||
* [Tipi di fotogramma](#tipi-di-fotogramma)
|
||||
+ [I Frame (intra, keyframe)](#i-frame-intra-keyframe)
|
||||
+ [P Frame (predicted)](#p-frame-predicted)
|
||||
- [Esercizio: un video con un solo I-frame](#esercizio-un-video-con-un-solo-i-frame)
|
||||
+ [B Frame (bi-predictive)](#b-frame-bi-predictive)
|
||||
- [Esercizio: confronta video con e senza B-frame](#esercizio-confronta-video-con-e-senza-b-frame)
|
||||
+ [Sommario](#sommario)
|
||||
* [Ridondanza temporale (predizione inter-frame)](#ridondanza-temporale-predizione-inter-frame)
|
||||
- [Esercizio: vedere i vettori di movimento](#esercizio-vedere-i-vettori-del-moto)
|
||||
* [Ridondanza spaziale (predizione intra-frame)](#ridondanza-spaziale-predizione-intra-frame)
|
||||
- [Esercizio: vedere la predizione intra-frame](#esercizio-vedere-la-predizione-intra-frame)
|
||||
- [Come funziona un codec video?](#come-funziona-un-codec-video)
|
||||
* [Cosa? Perché? Come?](#cosa-perch%C3%A9-come)
|
||||
* [Storia](#storia)
|
||||
+ [La nascita di AV1](#la-nascita-di-av1)
|
||||
* [Un codec generico](#un-codec-generico)
|
||||
* [1° passo - partizionamento dell'immagine](#1-passo---partizionamento-dellimmagine)
|
||||
+ [Esercizio: vedere le partizioni](#esercizio-vedere-le-partizioni)
|
||||
* [2° passo - predizioni](#2-passo---predizioni)
|
||||
* [3° passo - trasformazione](#3-passo---trasformazione)
|
||||
+ [Esercizio: scartare diversi coefficienti](#esercizio-scartare-diversi-coefficienti)
|
||||
* [4° passo - quantizzazione](#4-passo---quantizzazione)
|
||||
+ [Esercizio: quantizzazione](#esercizio-quantizzazione)
|
||||
* [5° passo - codifica dell'entropia](#5-passo---codifica-dellentropia)
|
||||
+ [Codifica VLC](#codifica-vlc)
|
||||
+ [Codifica aritmetica](#codifica-aritmetica)
|
||||
+ [Esercizio: CABAC vs CAVLC](#esercizio-cabac-vs-cavlc)
|
||||
* [6° passo - formato bitstream](#6-passo---formato-bitstream)
|
||||
+ [Bitstream di H.264](#bitstream-di-h264)
|
||||
+ [Esercizio: ispezionare il bitstream H.264](#esercizio-ispezionare-il-bitstream-h264)
|
||||
* [Ripasso](#ripasso)
|
||||
* [Come fa H.265 a comprimere più di H.264?](#come-fa-h265-a-comprimere-pi%C3%B9-di-h264)
|
||||
- [Streaming online](#streaming-online)
|
||||
* [Architettura generale](#architettura-generale)
|
||||
* [Download progressivo e download adattivo](#download-progressivo-vs-streaming-adattivo)
|
||||
* [Protezione dei contenuti](#protezione-dei-contenuti)
|
||||
- [Come usare jupyter](#come-usare-jupyter)
|
||||
- [Conferenze](#conferenze)
|
||||
- [Riferimenti](#riferimenti)
|
||||
|
||||
# Terminologia di base
|
||||
|
||||
Un'**immagine** può essere pensata come una **matrice bidimensionale**. Se pensiamo al fatto che ci sono anche i **colori**, possiamo evolvere questa idea pensando l'immagine come una **matrice tridimensionale**, dove la **terza dimensione** (o le dimensioni aggiuntive) viene utilizzata per memorizzare le **informazioni sul colore**.
|
||||
|
||||
Se scegliamo di rappresentare i colori utilizzando i [tre colori primari (rosso, verde e blu)](https://it.wikipedia.org/wiki/Colore_primario), possiamo definire tre piani: uno per il **rosso**, uno per il **verde** e uno per il **blu**.
|
||||
|
||||

|
||||
|
||||
Chiameremo ogni punto di questa matrice un **pixel** (dall'inglese *picture element*). Un pixel rappresenta l'**intensità** (che in genere è un valore numerico) di un determinato colore. Ad esempio, un **pixel rosso** può essere rappresentato con zero verde, zero blu e il massimo rosso possibile. Un **pixel di colore rosa** può essere formato con una combinazione di tre colori: usando una rappresentazione numerica in un intervallo che va da 0 a 255, il rosa può essere definito come **Rosso=255, Verde=192 e Blu=203**.
|
||||
|
||||
> #### Altri modi per codificare un'immagine a colori
|
||||
> Si possono utilizzare molti altri modelli per rappresentare i colori che compongono un'immagine. Potremmo ad esempio utilizzare una tavolozza di colori (con un indice associato a ciascun colore), rappresentando poi i pixel colorati con l'indice del colore nella tavolozza. In questo modo ogni pixel richiederebbe soltanto un byte di memoria, anziché tre byte come nel caso del modello RGB. Il vantaggio di un modello a _palette_ è quello di occupare meno memoria, riducendo però il numero di colori a disposizione.
|
||||
>
|
||||
> 
|
||||
|
||||
Per fare un esempio, guarda le immagini qui sotto. La prima figura è completamente colorata. Le altre mostrano rispettivamente i piani (o canali) rosso, verde e blu, in scala di grigi.
|
||||
|
||||

|
||||
|
||||
Possiamo notare che il **colore rosso** è quello che **contribuisce di più** a creare il colore finale (si notino le parti più chiare nella seconda figura, sotto "Red"), mentre il **colore blu** contribuisce prevalentemente a rendere il colore degli **occhi di Mario** e parte dei suoi vestiti (ultima figura a destra). Si può anche notare come nessun canale RGB dia un forte contributo a realizzare i colori scuri, come i baffi di Mario.
|
||||
|
||||
Ogni colore richiede un certo numero di bit per essere rappresentato. Questo valore si chiama **profondità di bit**. Se ad esempio decidiamo di utilizzare **8 bit** per canale RGB (potendo rappresentare quindi valori che vanno da 0 a 255), avremo una **profondità di colore** di **8 * 3 = 24 bit**, per un totale di 2<sup>24</sup> colori diversi.
|
||||
|
||||
> **È molto interessante** imparare [come un'immagine viene catturata dal mondo reale e convertita in bit](http://www.cambridgeincolour.com/tutorials/camera-sensors.htm).
|
||||
|
||||
Un'altra proprietà delle immagini è la **risoluzione**, cioè il numero di pixel per ogni dimensione. Viene spesso indicata utilizzando la notazione "larghezza x altezza", ad esempio **4x4** per indicare un'immagine larga 4 pixel e alta 4 pixel.
|
||||
|
||||

|
||||
|
||||
> #### Esercizio: sperimentare con le immagini e i colori
|
||||
> Puoi esercitarti [con le immagini e i colori](/image_as_3d_array.ipynb) utilizzando [jupyter](#how-to-use-jupyter) (python, numpy, matplotlib, ecc.).
|
||||
>
|
||||
> Puoi anche imparare [come funzionano i filtri (rilevazione dei contorni, nitidezza, sfocatura, ecc.)](/filters_are_easy.ipynb).
|
||||
|
||||
Lavorando con immagini e video incontreremo anche una proprietà che si chiama **rapporto d'aspetto**, che descrive la relazione di proporzionalità tra la larghezza e l'altezza di un'immagine o di un pixel.
|
||||
|
||||
Quando senti dire che un film o un'immagine è in 16:9, di solito ci si riferisce al **rapporto d'aspetto dell'immagine** (anche chiamato *DAR*, dall'inglese *Display Aspect Ratio*). Tuttavia, anche i pixel possono avere forme diverse, per cui si parla di rapporto d'aspetto anche per i pixel (più precisamente *PAR*, dall'inglese **Pixel Aspect Ratio**).
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
> #### I DVD hanno un DAR 4:3
|
||||
> Anche se la risoluzione video di un DVD è 704x480, il rapporto d'aspetto è 4:3, perché i pixel hanno un PAR di 10:11 (704x10/480x11).
|
||||
|
||||
Infine, possiamo definire un **video** come una **successione di *n* fotogrammi per unità di tempo**. Il valore *n* è la frequenza dei fotogrammi (*frame rate* in inglese), spesso abbreviata con FPS (fotogrammi al secondo).
|
||||
|
||||

|
||||
|
||||
Il numero dei bit necessari per rappresentare un secondo di video è chiamato **bitrate**, o meno comunemente *frequenza di bit*.
|
||||
|
||||
> bitrate = larghezza * altezza * profondità di bit * fotogrammi al secondo
|
||||
|
||||
Ad esempio, un video con 30 fotogrammi al secondo e 24 bit per pixel, con una risoluzione di 480x240 ha bisogno (se non utilizziamo nessun tipo di compressione) di **82˙944˙000 bit al secondo**, cioè 82,944 Mbps (il calcolo è 30x480x240x24 byte).
|
||||
|
||||
Quando il **bitrate** rimane quasi uguale nel tempo, parliamo di **bitrate costante (CBR)**, mentre quando varia di **bitrate variabile (VBR)**.
|
||||
|
||||
> Il grafico mostra il bitrate di un video codificato in modalità VBR limitata (dai valori min e max). Si può notare come il bitrate è più basso quando il fotogramma è nero.
|
||||
>
|
||||
> 
|
||||
|
||||
Molto tempo fa è stata inventata una tecnica per **raddoppiare il framerate percepito** da chi sta guardando un video, **senza richiedere l'utilizzo di dati aggiuntivi**. Questa tecnica è conosciuta come **interlacciamento**. Semplificando, in un video interlacciato metà dell'immagine è contenuta in un fotogramma, mentre l'altra metà nel fotogramma successivo.
|
||||
|
||||
Al giorno d'oggi la maggior parte degli schermi utilizza la **scansione progressiva**, una tecnica per cui la trasmissione, memorizzazione e visualizzazione delle immagini in movimento avviene disegnando progressivamente e in sequenza tutte le linee che compongono il fotogramma.
|
||||
|
||||

|
||||
|
||||
A questo punto abbiamo un'idea di come un'**immagine** viene rappresentata digitalmente, come i suoi **colori** sono disposti, quanti **bit al secondo** sono richiesti per mostrare un video, con bitrate costante (CBR) o variabile (VBR), e cosa sono i concetti di **risoluzione**, **framerate** (FPS), interlacciamento, PAR, ecc.
|
||||
|
||||
> #### Esercizio: controllare le proprietà di un file video
|
||||
> Puoi vedere la maggior parte delle proprietà che abbiamo appena visto [usando ffmpeg oppure mediainfo](https://github.com/leandromoreira/introduction_video_technology/blob/master/encoding_pratical_examples.md#inspect-stream) su un file video.
|
||||
|
||||
# Rimozione delle informazioni ridondanti
|
||||
|
||||
Abbiamo imparato che memorizzare un video senza nessuna compressione è impraticabile. **Un'ora di video** a una risoluzione 720p30 (720 linee verticali con scansione progressiva, con 30 fotogrammi al secondo) **richiederebbe 278 GB**<sup>\*</sup>. Dato che utilizzando i normali algoritmi di compressione lossless (come DEFLATE, utilizzato in PKZIP, Gzip e PNG) non otterremmo una diminuzione significativa della dimensione del file, dobbiamo trovare altri modi per comprimere il video.
|
||||
|
||||
> <sup>\*</sup>Si può ottenere questo risultato moltiplicando 1280 x 720 x 24 x 30 x 3600 (larghezza, altezza, bit per pixel, fps e durata in secondi).
|
||||
|
||||
Per farlo possiamo sfruttare il modo in cui la nostra vista funziona. Possiamo infatti sfruttare il fatto che l'occhio riesce a distinguere meglio diverse luminosità che diversi colori. È importante anche considerare le **ripetizioni nel tempo** (un video contiene molti fotogrammi molto simili, con poche differenze) e le **ripetizioni all'interno delle immagini** (un fotogramma può contenere aree che hanno lo stesso colore o un colore molto simile).
|
||||
|
||||
## I colori, la luminanza e i nostri occhi
|
||||
|
||||
I nostri occhi sono [più sensibili alla luminosità che ai colori](http://vanseodesign.com/web-design/color-luminance/), puoi vederlo tu stesso con l'immagine seguente.
|
||||
|
||||

|
||||
|
||||
Se nell'immagine a sinistra non riesci a vedere che **i colori dei quadrati A e B sono identici**, è normale. È il nostro cervello che ci induce a **prestare più attenzione alla luce e al buio che al colore**. Nell'immagine a destra i due quadrati sono collegati con una striscia dello stesso colore dei quadrati, così riusciamo molto più facilmente a vedere che A e B sono effettivamente dello stesso colore.
|
||||
|
||||
> **Spiegazione semplificata del funzionamento dell'occhio**
|
||||
>
|
||||
> L'occhio [è un organo complesso](http://www.biologymad.com/nervoussystem/eyenotes.htm): è composto da molte parti ma siamo prevalentemente interessati alle cellule fotorecettrici, i coni e i bastoncelli. L'occhio contiene [circa 120 milioni di bastoncelli e 6 milioni di coni](https://it.wikipedia.org/wiki/Fotorecettore).
|
||||
>
|
||||
> In modo **molto semplificato**, proviamo ad associare colori e luminosità alle parti degli occhi. I **[bastoncelli](https://it.wikipedia.org/wiki/Bastoncello) sono quasi solo responsabili della luminosità**, mentre **[i coni](https://it.wikipedia.org/wiki/Cellula_cono) sono responsabili del colore**. I coni sono di tre tipi, ognuno con un pigmento diverso e sensibile a un colore diverso. In particolare, esistono [coni S (blu), coni M (verde) e coni L (rosso)](https://upload.wikimedia.org/wikipedia/commons/1/1e/Cones_SMJ2_E.svg).
|
||||
>
|
||||
> Dato che l'occhio ha molti più bastoncelli (luminosità) che coni (colore), si può dedurre che l'occhio è più bravo a distinguere il chiaro dallo scuro che i colori.
|
||||
>
|
||||
> 
|
||||
>
|
||||
> **Funzioni di sensibilità al contrasto**
|
||||
>
|
||||
> Ricercatori di psicologia sperimentale e altri campi hanno sviluppato molte teorie sull'occhio umano. Una di queste si chiama "funzioni di sensibilità al contrasto". Queste funzioni riguardano il legame spaziotemporale della luce, il loro valore con una certa quantità di luce iniziale, e quanto cambiamento è richiesto prima che un osservatore si accorga che c'è stato un cambiamento. Il plurale della parola "funzioni" è dovuto al fatto che possiamo usare queste funzioni non solo per studiare il bianco e il nero, ma anche i colori. Il risultato di questi esperimenti mostra che nella maggior parte dei casi l'occhio è più sensibile alla luce che al colore.
|
||||
|
||||
Ora che sappiamo che siamo più sensibili alla lumimanza (la luminosità di un'immagine), possiamo provare a sfruttare questo fatto.
|
||||
|
||||
### Modelli di colore
|
||||
|
||||
Abbiamo inizialmente imparato [come colorare le immagini](#terminologia-di-base) usando il **modello RGB**, ma esistono altri modelli. Ad esempio esiste un modello che separa la luminanza (la luminosità) dalla crominanza (i colori), ed è conosciuto come **YCbCr**<sup>\*</sup>.
|
||||
|
||||
> <sup>\*</sup>esistono anche altri modelli che fanno la stessa distinzione.
|
||||
|
||||
Questo modello di colore utilizza la **Y** per rappresentare la luminosità, e due canali **Cb** (*chroma blue*) e **Cr** (*chroma red*) per i colori. Il modello [YCbCr](https://it.wikipedia.org/wiki/YCbCr) può essere derivato da RGB, e viceversa. Con i tre canali possiamo creare immagini pienamente colorate, come mostrato nell'immagine:
|
||||
|
||||

|
||||
|
||||
### Conversione tra YCbCr e RGB
|
||||
|
||||
Qualcuno si potrebbe chiedere: "**come è possibile produrre tutti i colori senza usare il verde?**"
|
||||
|
||||
Per rispondere a questa domanda, proveremo a fare una conversione da RGB a YCbCr. Utilizzeremo i coefficienti definiti dallo **[standard BT.601](https://it.wikipedia.org/wiki/BT.601)**, una delle raccomandazioni del gruppo [ITU-R](https://it.wikipedia.org/wiki/ITU-R)<sup>\*</sup>.
|
||||
|
||||
Il primo passo è **calcolare la luminanza**, utilizzando le costanti suggerite dall'ITU e i valori RGB.
|
||||
|
||||
```
|
||||
Y = 0.299R + 0.587G + 0.114B
|
||||
```
|
||||
|
||||
Ora che abbiamo la luminanza, possiamo **dividere i colori** (colore blu e rosso):
|
||||
|
||||
```
|
||||
Cb = 0.564(B - Y)
|
||||
Cr = 0.713(R - Y)
|
||||
```
|
||||
|
||||
Possiamo anche **tornare indietro** facendo la conversione inversa, e anche **ottenere il valore del verde utilizzando YCbCr**.
|
||||
|
||||
```
|
||||
R = Y + 1.402Cr
|
||||
B = Y + 1.772Cb
|
||||
G = Y - 0.344Cb - 0.714Cr
|
||||
```
|
||||
|
||||
> <sup>\*</sup> i gruppi e gli standard sono comuni nel mondo del video digitale, di solito definiscono quali sono gli standard da usare, ad esempio [cosa si intende con 4K? quale framerate dovrei usare? quale risoluzione e modello di colore?](https://it.wikipedia.org/wiki/BT.2020)
|
||||
|
||||
In genere i display (monitor, tv, schermi, ecc.) utilizzano **solo il modello RGB**, anche se con geometrie dei pixel diverse, come si vede nelle immagini, che rappresentano schermi di tipo diverso, ingranditi.
|
||||
|
||||

|
||||
|
||||
### Sottocampionamento della crominanza
|
||||
|
||||
Con la rappresentazione dell'immagine in termini di luminanza e crominanza, possiamo trarre vantaggio dalle caratteristiche dell'occhio (che privilegiano la luminanza) per rimuovere selettivamente delle informazioni. La tecnica di **sottocampionamento della crominanza** fa proprio questo, e cioè utilizza **meno risoluzione per la crominanza rispetto alla luminanza**.
|
||||
|
||||

|
||||
|
||||
Quanto dovremmo ridurre la risoluzione della crominanza? Si scopre che esistono già degli schemi che descrivono come gestire la risoluzione e l'unione `colore finale = Y + Cb + Cr`.
|
||||
|
||||
Questi schemi sono noti come **sistemi di sottocampionamento** e sono espressi utilizzando un rapporto composto da tre valori. In particolare `a:x:y` definisce la risoluzione di crominanza di un blocco di pixel di luminanza di dimensione `a x 2` pixel.
|
||||
|
||||
* `a` numero di pixel orizzontali di riferimento per il campionamento (di solito 4)
|
||||
* `x` numero di campioni di crominanza nella prima riga di `a` pixel (risoluzione orizzontale in relazione a `a`)
|
||||
* `y` numero di cambiamenti di campioni di crominanza tra la prima e la seconda riga della griglia `a x 2`
|
||||
|
||||
> C'è un'eccezione a questa definizione, in particolare nello schema 4:1:0, che prevede un singolo campione di crominanza per ogni blocco `4 x 4` di luminanza.
|
||||
|
||||
Tra gli schemi più comuni nei codec moderni ci sono **4:4:4** *(nessun sottocampionamento)*, **4:2:2, 4:1:1, 4:2:0, 4:1:0 and 3:1:1**.
|
||||
|
||||
> **Unione di YCbCr 4:2:0**
|
||||
>
|
||||
> Ecco un esempio di come funziona l'unione di un'immagine usando YCbCr con schema di sottocampionamento della crominanza 4:2:0. Nota che vengono utilizzati soltanto 12 bit per pixel.
|
||||
>
|
||||
> 
|
||||
|
||||
Le immagini che seguono mostrano la stessa foto codificata con diversi tipi di sottocampionamento della crominanza. Le immagini della prima riga sono quelle finali, mentre quelle della seconda riga mostrano la risoluzione della crominanza. Il risultato è ottimo dato che la perdita di qualità nell'immagine a colori è molto bassa.
|
||||
|
||||

|
||||
|
||||
Prima abbiamo calcolato che sono necessari [278 GB di spazio per archiviare un file video dalla durata di un'ora, con risoluzione 720p e framerate di 30 fps](#rimozione-delle-informazioni-ridondanti). Se utilizziamo il modello colore **YCbCr 4:2:0**, possiamo **dimezzare la dimensione (139 GB)**<sup>\*</sup>, anche se siamo ben lontani dall'ideale.
|
||||
|
||||
> <sup>\*</sup>si ottiene questo valore moltiplicando tra loro larghezza, altezza, bit per pixel e fps. Con il modello RGB avevamo bisogno di 24 bit per pixel, ora ne abbiamo bisogno soltanto 12.
|
||||
|
||||
<br/>
|
||||
|
||||
> ### Esercizio: vedere l'istogramma YCbCr
|
||||
> Puoi controllare [l'istogramma di un video YCbCr con ffmpeg](/encoding_pratical_examples.md#generates-yuv-histogram). Ad esempio, in questa scena il colore blu porta un alto contributo, come evidenziato dall'[istogramma](https://it.wikipedia.org/wiki/Istogramma).
|
||||
>
|
||||
> 
|
||||
|
||||
## Tipi di fotogramma
|
||||
|
||||
Prima di occuparci della **ridondanza delle informazioni nel tempo**, chiariamo la terminologia che useremo. Supponiamo di avere un filmato con 30 fps, i cui primi 4 fotogrammi sono:
|
||||
|
||||
  
|
||||

|
||||
|
||||
È evidente che ci sono **molte ripetizioni** all'interno e tra i fotogrammi. Ad esempio lo sfondo blu non cambia tra il primo e l'ultimo fotogramma. Per sfruttare questa caratteristica dei fotogrammi, possiamo **categorizzare in modo astratto** i fotogrammi in [tre tipi diversi](https://it.wikipedia.org/wiki/Tipi_di_fotogramma_nella_compressione_video).
|
||||
|
||||
### I-frame (intra, keyframe)
|
||||
|
||||
Un I-frame (chiamato anche *reference frame*, *keyframe*, *intra-frame*) è un fotogramma **indipendente**. Non si affida a nessun'altra informazione esterna per essere renderizzato. È come una foto statica. Di solito il primo fotogramma di un video è un I-frame, ma vedremo che ce ne possono essere più di uno in un video, mischiati tra gli altri fotogrammi di tipo diverso.
|
||||
|
||||

|
||||
|
||||
### P-frame (predicted)
|
||||
|
||||
Un P-frame (*fotogramma predetto*) sfrutta il fatto che quasi sempre il fotogramma può essere **renderizzato utilizzando il fotogramma precedente**. Ad esempio, nel secondo fotogramma l'unico cambiamento rispetto al precedente è il movimento della palla. Possiamo quindi **ricostruire questo fotogramma utilizzando le differenze rispetto al precedente**.
|
||||
|
||||
 <- 
|
||||
|
||||
> #### Esercizio: un video con un solo I-frame
|
||||
> Dato che un P-frame utilizza meno dati rispetto a un I-frame, perché non possiamo codificare un intero video [usando solo un I-frame e poi solo P-frame?](/encoding_pratical_examples.md#1-i-frame-and-the-rest-p-frames)
|
||||
>
|
||||
> Per esercizio codifica il video esempio, riproducilo e **salta a una posizione avanzata** del video. Noterai che sarà **richiesto del tempo** perché il player completi l'operazione di *seek*. Questo avviene perché un **P-frame ha bisogno di un fotogramma di riferimento** (ad esempio un I-Frame, ma non per forza) per essere renderizzato.
|
||||
>
|
||||
> Un altro veloce esperimento che puoi fare è [codificare un video sia utilizzando un singolo I-frame che impostato un I-frame ogni 2 secondi](/encoding_pratical_examples.md#1-i-frames-per-second-vs-05-i-frames-per-second), e confrontare la **dimensione dei due file risultanti**.
|
||||
|
||||
### B-frame (bi-predictive)
|
||||
|
||||
E se potessimo fare riferimento sia a fotogrammi passati che futuri, per ottenere una compressione migliore? È proprio come funzionano i B-frame, o frame bi-predittivi.
|
||||
|
||||
 <-  -> 
|
||||
|
||||
> #### Esercizio: confronta video con e senza B-frame
|
||||
> Genera due video, uno con i B-frame e uno [senza B-frame](/encoding_pratical_examples.md#no-b-frames-at-all), e confronta la differenza di dimensione del file e la qualità dei risultati.
|
||||
|
||||
### Sommario
|
||||
|
||||
Diversi tipi di frame possono essere utilizzati per **fornire una migliore compressione**. Scopriremo meglio come nella prossima sezione, ma per ora è importante capire che **gli I-frame sono costosi, i P-frame un po' meno, e infine i B-frame sono i più leggeri**.
|
||||
|
||||

|
||||
|
||||
## Ridondanza temporale (predizione inter-frame)
|
||||
|
||||
Esploriamo le possibilità che abbiamo per cercare di ridurre la **ripetizione delle informazioni nel tempo**. Questo tipo di ridondanza può essere affrontata usando la **predizione tra fotogrammi** (*inter-frame prediction* o *inter prediction*).
|
||||
|
||||
L'obiettivo è **utilizzare meno bit** per codificare la sequenza di fotogrammi 0 e 1.
|
||||
|
||||

|
||||
|
||||
Una cosa che potremmo fare è **sottrarre il fotogramma 1 dal fotogramma 0**, in modo da ottenere soltanto il **residuo da codificare**.
|
||||
|
||||

|
||||
|
||||
E se ti dicessi che esiste un **metodo migliore**, che consente di utilizzare ancora meno informazione? Consideriamo il `fotogramma 0` come un insieme di partizioni (riquadri) ben definite, e proviamo a creare un'associazione tra i blocchi del `fotogramma 0` e il `fotogramma 1`. Possiamo pensare a questo meccanismo come una **stima del moto**.
|
||||
|
||||
> ### Da Wikipedia: compensazione del moto dei blocchi
|
||||
> "La **compensazione del moto dei blocchi** divide il fotogramma corrente in blocchi non sovrapposti, e il vettore di compensazione del moto **indica da dove si sono spostati quei blocchi** (una convinzione comune ma errata è che il fotogramma precedente viene diviso in blocchi non sovrapposti, e i vettori di compensazione del moto indicano dove i blocchi si sposteranno). I blocchi sorgente tipicamente si sovrappongono nel fotogramma sorgente. Alcuni algoritmi di compressione video costruiscono il fotogramma corrente utilizzando pezzi di diversi fotogrammi creati precedentemente."
|
||||
|
||||

|
||||
|
||||
Possiamo stimare che la palla si è spostata dalla posizione `x=0, y=25` alla posizione `x=6, y=26`. I valori di **x** e **y** determinano i **vettori del moto**. Un passo aggiuntivo che possiamo fare per risparmiare spazio è **codificare soltanto il vettore di spostamento ottenuto dalla differenza** tra l'ultima posizione del blocco e quella predetta. Nell'esempio sopra il vettore del moto sarebbe quindi `x=6 (6-0), y=1 (26-25)`.
|
||||
|
||||
> In una situazione di codifica reale, **la palla sarebbe divisa tra più partizioni**, ma il procedimento è lo stesso.
|
||||
|
||||
Gli oggetti nel fotogramma **si muovono in 3 dimensioni**, cioè ad esempio la palla può diventare più piccola se si muove verso lo sfondo. È quindi normale non trovare **la corrispondenza perfetta** tra blocchi. Ad esempio questo è il risultato della nostra stima del moto in confronto alla figura reale:
|
||||
|
||||

|
||||
|
||||
Il vantaggio di applicare la tecnica della **stima del moto** è che **i dati da codificare sono di meno** in confronto a una semplice differenza tra fotogrammi.
|
||||
|
||||

|
||||
|
||||
> ### Come funziona realmente la compensazione del moto
|
||||
> La tecnica appena vista viene applicata a tutti i blocchi, ma probabilmente la palla dell'esempio verrebbe partizionata in più di un blocco.
|
||||
> 
|
||||
> Fonte: https://web.stanford.edu/class/ee398a/handouts/lectures/EE398a_MotionEstimation_2012.pdf
|
||||
|
||||
Puoi esercitarti con questi concetti [usando jupyter](/frame_difference_vs_motion_estimation_plus_residual.ipynb).
|
||||
|
||||
> #### Esercizio: vedere i vettori del moto
|
||||
> Possiamo generare un video [che mostra la predizione tra frame (e i vettori del moto) con ffmpeg.](/encoding_pratical_examples.md#generate-debug-video)
|
||||
>
|
||||
>  con ffmpeg")
|
||||
>
|
||||
> In alternativa possiamo usare il software [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (è a pagamento ma esiste una versione di prova che limita l'analisi ai primi 10 fotogrammi).
|
||||
>
|
||||
> 
|
||||
|
||||
## Ridondanza spaziale (predizione intra-frame)
|
||||
|
||||
Se analizziamo un **singolo fotogramma** di un video noteremo che ci sono **molte aree correlate**.
|
||||
|
||||

|
||||
|
||||
Facciamo un esempio. Questa scena è composta prevalentemente dai colori blu e bianco:
|
||||
|
||||

|
||||
|
||||
Questo fotogramma è un `I-frame`, per cui **non possiamo usare fotogrammi precedenti** per costruirlo. Possiamo però comunque comprimerlo. Proviamo ad esempio a codificare il blocco evidenziato in rosso. Se guardiamo **intorno al blocco** possiamo **stimare** che c'è una **tendenza di colore attorno al blocco**.
|
||||
|
||||

|
||||
|
||||
Possiamo ad esempio **predire** che i pixel colorati sopra il blocco **continuino allo stesso modo verticalmente**. In altre parole **i pixel del blocco che hanno colore sconosciuto assumeranno attraverso la predizione il colore dei pixel che si trovano sopra** (in questo caso).
|
||||
|
||||

|
||||
|
||||
La **predizione che abbiamo fatto può essere sbagliata**, per cui dopo aver applicato la predizione dobbiamo **sottrarre i valori reali** dei pixel, in modo da ottenere un blocco residuo. Il risultato è una matrice molto più facilmente comprimibile in confronto all'originale.
|
||||
|
||||

|
||||
|
||||
> #### Esercizio: vedere la predizione intra-frame
|
||||
> Puoi [generare un video con i macro-blocchi e le sue predizioni con ffmpeg](/encoding_pratical_examples.md#generate-debug-video). Consulta la documentazione di ffmpeg per comprendere meglio [il significato dei colori dei blocchi](https://trac.ffmpeg.org/wiki/Debug/MacroblocksAndMotionVectors).
|
||||
>
|
||||
>  con ffmpeg")
|
||||
>
|
||||
> In alternativa puoi anche usare il software [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (è a pagamento ma esiste una versione di prova che limita l'analisi ai primi 10 fotogrammi).
|
||||
>
|
||||
> 
|
||||
|
||||
# Come funziona un codec video?
|
||||
|
||||
## Cosa? Perché? Come?
|
||||
|
||||
**Cos'è?** È un software o un dispositivo hardware che comprime o decomprime un video digitale. **Perché?** Il mercato e la società richiedono video di qualità alta con banda o spazio di archiviazione limitati. Ti ricordi che abbiamo [calcolato la banda necessaria](#terminologia-di-base) per trasmettere un video con 30 fotogrammi al secondo, 24 bit per pixel e una risoluzione di 480x240 pixel? Risultava **83 Mbps**, senza applicare alcuna compressione. I codec sono l'unico modo per fornire video HD/Full HD/UHD alle tv e tramite Internet. **Come?** Stiamo per dare un'occhiata alle principali tecniche usate.
|
||||
|
||||
> **CODEC vs Container**
|
||||
>
|
||||
> Un errore che viene spesso fatto dai principianti è confondere il CODEC video con il [contenitore video](https://it.wikipedia.org/wiki/Formato_contenitore). Possiamo pensare al **contenitore** come un formato "wrapper" che contiene i metadati sulle tracce video (e audio), e il vero e proprio **video compresso** come carico pagante (*payload*).
|
||||
>
|
||||
> Solitamente l'estensione di un file video determina il suo formato contenitore. Ad esempio, un file `video.mp4` indica con molta probabilità il formato **[MPEG-4 Part 14](https://it.wikipedia.org/wiki/MPEG-4_Part_14)**, mentre un file chiamato `video.mkv` si riferisce al formato **[Matroska](https://it.wikipedia.org/wiki/Matroska)**. Per controllare con certezza il codec e il formato contenitore di un file possiamo utilizzare [ffmpeg oppure mediainfo](/encoding_pratical_examples.md#inspect-stream).
|
||||
|
||||
## Storia
|
||||
|
||||
Prima di passare ad analizzare il funzionamento interno di un codec generico, facciamo un salto indietro nella storia per comprendere meglio alcuni vecchi codec.
|
||||
|
||||
Il codec video [H.261](https://it.wikipedia.org/wiki/H.261) nacque nel 1990 (tecnicamente nel 1988) e fu progettato per funzionare con **bitrate di 64 kbit/s**. Il codec utilizzava già idee come il sottocampionamento della crominanza, i macro-blocchi, ecc. Nell'anno 1955 lo standard del codec video **H.263** fu pubblicato, poi modificato ed esteso fino al 2001.
|
||||
|
||||
Nel 2003 la prima versione del codec **H.264/AVC** fu completata. Nello stesso anno, un'azienda chiamata **TrueMotion** rilasciò un altro codec per la compressione video, lossy e **royalty-free**, chiamato **VP3**. Nel 2008, **Google acquisto l'azienda**, rilasciando **VP8** nello stesso anno. Nel dicembre del 2012, Google rilasciò **VP9**, oggi **supportato da circa ¾ dei browser sul mercato** (mobile incluso).
|
||||
|
||||
**[AV1](https://it.wikipedia.org/wiki/AOMedia_Video_1)** è un nuovo codec video **royalty-free** e open source che è stato progettato dalla [Alliance for Open Media (AOMedia)](http://aomedia.org/), composta da grandi aziende come **Google, Mozilla, Microsoft, Amazon, Netflix, AMD, ARM, NVidia, Intel e Cisco**. La **prima versione** 0.1.0 del codec di riferimento è stata pubblicata il 7 aprile 2016.
|
||||
|
||||

|
||||
|
||||
> #### La nascita di AV1
|
||||
>
|
||||
> All'inizio del 2015, Google stava lavorando su [VP10](https://en.wikipedia.org/wiki/VP9#Successor:_from_VP10_to_AV1), Xiph (Mozilla) su [Daala](https://xiph.org/daala/) e Cisco ha reso open source il suo codec video royalty-free chiamato [Thor](https://tools.ietf.org/html/draft-fuldseth-netvc-thor-03).
|
||||
>
|
||||
> MPEG LA ha annunciato dei limiti annuali per HEVC (H.265) e canoni di utilizzo 8 volte superiori a H.264, per poi cambiare le regole di nuovo:
|
||||
> * **nessun limite annuale**,
|
||||
> * **commissione sui contenuti** (lo 0,5% delle entrate)
|
||||
> * **commissioni per unità circa 10 volte più alte di H.264**.
|
||||
>
|
||||
> La [*Alliance for Open Media*](http://aomedia.org/about-us/) è stata creata da aziende produttrici di hardware (Intel, AMD, ARM , Nvidia, Cisco), aziende che forniscono contenuti (Google, Netflix, Amazon), browser (Google, Mozilla), e altre.
|
||||
>
|
||||
> Le aziende si sono poste un obiettivo comune: un video codec royalty-free. È quindi nato AV1, con un [sistema di licenze molto più semplice](http://aomedia.org/license/patent/). **Timothy B. Terriberry** ha fatto [un'ottima presentazione](https://www.youtube.com/watch?v=lzPaldsmJbk) (fonte di questa sezione) sul concepimento di AV1, il modello di licenza e lo stato attuale del codec.
|
||||
>
|
||||
> Ti sorprenderà sapere che puoi **analizzare il codec AV1 tramite il tuo browser**, andando alla pagina http://aomanalyzer.org/
|
||||
>
|
||||
> 
|
||||
>
|
||||
> P.S.: se vuoi imparare di più sulla storia dei codec è importante conoscere le basi che stanno dietro ai [brevetti legati alla compressione video](https://www.vcodex.com/video-compression-patents/).
|
||||
|
||||
## Un codec generico
|
||||
|
||||
Introdurremo ora i **meccanismi principali che stanno dietro a un generico codec video**, ma che si applicano anche ai principali codec moderni come VP9, AV1 e HEVC. Tieni presente che la spiegazione sarà *molto* semplificata rispetto alla realtà, anche se useremo qualche esempio reale (come H.264) per mostrare il funzionamento di una tecnica.
|
||||
|
||||
## 1° passo - partizionamento dell'immagine
|
||||
|
||||
Il primo passo è **dividere il fotogramma** in molte **partizioni, sotto-partizioni** e via dicendo.
|
||||
|
||||

|
||||
|
||||
**Perché si fa?** Ci sono molte ragioni: ad esempio, dividendo l'immagine possiamo calcolare le predizioni più precisamente, e utilizzare le partizioni più piccole per le parti in movimento, mentre quelle più grandi per rappresentare sfondi statici.
|
||||
|
||||
Solitamente, i CODEC **organizzano le partizioni** in *slice* (o *tile*), *macro* (o *coding tree unit*) e tante altre sotto-partizioni. La dimensione massima di queste partizioni varia, ad esempio per HEVC è 64x64 pixel, per AVC (H.264) è 16x16, con le sotto-partizioni che possono essere piccole fino a 4x4 pixel.
|
||||
|
||||
Ti ricordi che i fotogrammi possono essere di **diverso tipo**? Si può **applicare la stessa idea anche ai blocchi**, per cui possiamo avere I-slice, B-slice, I-macroblock, ecc.
|
||||
|
||||
> ### Esercizio: vedere le partizioni
|
||||
> Puoi usare il software [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (è a pagamento ma esiste una versione di prova che limita l'analisi ai primi 10 fotogrammi). Ecco un esempio che mostra le [partizioni di VP9](/encoding_pratical_examples.md#transcoding).
|
||||
>
|
||||
> 
|
||||
|
||||
## 2° passo - predizioni
|
||||
|
||||
Ora che abbiamo le partizioni, possiamo usarle per fare le predizioni. Per la predizione [inter-frame](#ridondanza-temporale-predizione-inter-frame) dobbiamo raccogliere informazioni sui **vettori del moto e sul residuo**, mentre per la predizione [intra-frame](#ridondanza-spaziale-predizione-intra-frame) ci servono **la direzione della predizione e il residuo**.
|
||||
|
||||
## 3° passo - trasformazione
|
||||
|
||||
Una volta che abbiamo il blocco residuo (ottenuto da `partizione predetta - partizione reale`), possiamo **trasformarlo** in un modo che ci consenta di vedere **quali pixel possiamo scartare** pur mantenendo la **qualità generale**. Ci sono diverse trasformazioni che ci permettono di farlo.
|
||||
|
||||
Anche se esistono [molte altre trasformazioni](https://en.wikipedia.org/wiki/List_of_Fourier-related_transforms#Discrete_transforms), daremo uno sguardo più approfondito alla trasformata discreta del coseno (*DCT*). La [DCT](https://it.wikipedia.org/wiki/Trasformata_discreta_del_coseno) ci permette di:
|
||||
|
||||
* **convertire** blocchi di pixel in blocchi di **coefficienti di frequenza** della stessa dimensione
|
||||
* **compattare** l'energia, aiutandoci a eliminare la ridondanza spaziale
|
||||
* **invertire** il processo, cioè tornare a blocchi di pixel
|
||||
|
||||
> Il 2 febbraio 2017, Cintra, R. J. e Bayer, F. M hanno pubblicato l'articolo scientifico [DCT-like Transform for Image Compression Requires 14 Additions Only](https://arxiv.org/abs/1702.00817).
|
||||
|
||||
Non preoccuparti se non hai capito a pieno i benefici di ciascun punto, faremo qualche esperimento in modo da capire meglio il reale valore della trasformata.
|
||||
|
||||
Prendiamo il seguente **blocco di pixel** (8x8):
|
||||
|
||||

|
||||
|
||||
Che corrisponde alla seguente immagine (8x8):
|
||||
|
||||

|
||||
|
||||
**Applicando la DCT** a questo blocco di pixel otteniamo un **blocco dei coefficienti** (8x8):
|
||||
|
||||

|
||||
|
||||
Il blocco dei coefficienti ottenuto, convertito in un'immagine, appare così:
|
||||
|
||||

|
||||
|
||||
Come puoi vedere non assomiglia per niente all'immagine originale. Si può anche notare che il **primo coefficiente** è molto diverso dagli altri. Questo perché il primo coefficiente della DCT è quello che rappresenta **tutti i campioni** della matrice di ingresso, qualcosa di **simile a una media**.
|
||||
|
||||
Il blocco dei coefficienti ha un'interessante proprietà, e cioè che separa i componenti relativi alle alte frequenze da quelli delle basse frequenze.
|
||||
|
||||

|
||||
|
||||
In un'immagine, **la maggior parte dell'energia** è concentrata nelle [**basse frequenze**](https://web.archive.org/web/20150129171151/https://www.iem.thm.de/telekom-labor/zinke/mk/mpeg2beg/whatisit.htm), quindi dopo aver applicato la trasformata possiamo **scartare i coefficienti delle alte frequenze**, in modo da **ridurre la quantità di dati** richiesta per descrivere l'immagine, pur senza sacrificare troppo la qualità dell'immagine.
|
||||
|
||||
> la frequenza determina quando rapidamente un segnale cambia.
|
||||
|
||||
Proviamo ad applicare le conoscenze acquisite: convertiamo l'immagine originale nelle sue frequenze usando la DCT, e poi scartiamo i coefficienti meno importanti.
|
||||
|
||||
Per prima cosa, convertiamo il blocco nel **dominio della frequenza**.
|
||||
|
||||

|
||||
|
||||
Poi, scartiamo parte dei coefficienti (il 67%), prevalentemente nell'angolo in basso a destra del blocco.
|
||||
|
||||

|
||||
|
||||
Infine, ricostruiamo l'immagine utilizzando il blocco dei coefficienti modificato, e confrontiamo il risultato con l'immagine originale.
|
||||
|
||||

|
||||
|
||||
L'immagine a destra è simile a quella originale, ma introduce anche molte differenze. Abbiamo però **buttato via il 67,1875%** delle informazioni e comunque siamo in grado di ottenere un'immagine che assomiglia a quella originale. Il prossimo passo è capire come modificare i coefficienti in modo più intelligente, per ottenere così una migliore qualità dell'immagine.
|
||||
|
||||
> **Ogni coefficiente viene calcolato utilizzando tutti i pixel**
|
||||
>
|
||||
> È importante evidenziare che ogni coefficiente del blocco non corrisponde direttamente a un singolo pixel, ma è una somma pesata di tutti i pixel. Il grafico che segue mostra come il primo e il secondo coefficiente vengono calcolati, utilizzando persi che sono diversi per ogni indice.
|
||||
>
|
||||
> 
|
||||
>
|
||||
> Fonte: https://web.archive.org/web/20150129171151/https://www.iem.thm.de/telekom-labor/zinke/mk/mpeg2beg/whatisit.htm
|
||||
>
|
||||
> Puoi anche provare a [osservare visivamente la DCT con la formazione di un'immagine](/dct_better_explained.ipynb). Ad esempio, qua puoi vedere [la formazione della lettera A](https://en.wikipedia.org/wiki/Discrete_cosine_transform#Example_of_IDCT) utilizzando diversi pesi per i coefficienti.
|
||||
>
|
||||
> 
|
||||
|
||||
<br/>
|
||||
|
||||
> ### Esercizio: scartare diversi coefficienti
|
||||
> Puoi sperimentare con [la trasformata DCT](/uniform_quantization_experience.ipynb).
|
||||
|
||||
## 4° passo - quantizzazione
|
||||
|
||||
Quando scartiamo dei coefficienti, come abbiamo fatto alla fine dell'ultimo passo, stiamo già facendo una sorta di quantizzazione. Questo passo è quello in cui decidiamo quali informazioni "perdere", e lo facciamo **quantizzando i coefficienti per ottenere della compressione**.
|
||||
|
||||
Come possiamo quantizzare un blocco di coefficienti? Un metodo semplice potrebbe essere una quantizzazione uniforme, in cui prendiamo un blocco e **dividiamo tutti i valori per lo stesso numero** (10), per poi arrotondare.
|
||||
|
||||

|
||||
|
||||
Come possiamo **invertire** (ri-quantizzare) il blocco dei coefficienti? È sufficiente **moltiplicare i valori ottenuti per lo stesso numero** con cui li abbiamo divisi (10).
|
||||
|
||||

|
||||
|
||||
**Questo approccio non è però il migliore**, perché non tiene in considerazione l'importanza dei diversi coefficienti. Anziché un singolo valore per la divisione, potremmo utilizzare una **matrice di quantizzazione**, che sfrutterebbe quindi le proprietà della DCT quantizzando maggiormente l'angolo in basso a destra e in modo minore quello in alto a sinistra. La [compressione JPEG](https://www.hdm-stuttgart.de/~maucher/Python/MMCodecs/html/jpegUpToQuant.html) utilizza un metodo simile, e puoi vedere un esempio di matrice di quantizzazione [nel codice sorgente](https://github.com/google/guetzli/blob/master/guetzli/jpeg_data.h#L40) di un compressore JPEG.
|
||||
|
||||
> ### Esercizio: quantizzazione
|
||||
> Puoi sperimentare [con la quantizzazione](/dct_experiences.ipynb).
|
||||
|
||||
## 5° passo - codifica dell'entropia
|
||||
|
||||
Dopo aver quantizzato i dati (i blocchi/slice/fotogrammi), possiamo comprimerli ulteriormenti utilizzando metodi di compressione lossless (senza perdita). Ci sono moltissimi algoritmi per comprimere i dati, e andremo a vederne alcuni. Per comprendere a fondo i concetti legati alla compressione dei dati, una lettura consigliata è il fantastico libro [Understanding Compression: Data Compression for Modern Developers](https://www.amazon.it/Understanding-Compression-Data-Modern-Developers/dp/1491961538/).
|
||||
|
||||
### Codifica VLC:
|
||||
|
||||
Supponiamo di avere un flusso di simboli: **a**, **e**, **r** e **t**, con le seguenti probabilità (valori da 0 a 1) di comparire nel flusso.
|
||||
|
||||
| | a | e | r | t |
|
||||
|-------------|-----|-----|-----|-----|
|
||||
| probabilità | 0,3 | 0,3 | 0,2 | 0,2 |
|
||||
|
||||
Possiamo assegnare un codice binario (preferibilmente piccolo) al simbolo più probabile, e un codice più lungo ai simboli meno probabili.
|
||||
|
||||
| | a | e | r | t |
|
||||
|----------------|-----|-----|-----|------|
|
||||
| probabilità | 0,3 | 0,3 | 0,2 | 0,2 |
|
||||
| codice binario | 0 | 10 | 110 | 1110 |
|
||||
|
||||
Proviamo ora a comprimere il flusso rappresentato dalla parola **eat**. Assumendo di utilizzare 8 bit per ogni simbolo (carattere), avremmo bisogno di **24 bit** per rappresenta la parola, senza utilizzare nessun metodo di compressione. Ma se invece utilizziamo i codici binari associati alle lettere, possiamo risparmiare spazio.
|
||||
|
||||
Il primo passo è codificare il simbolo **e**, che corrisponde a `10`, per poi passare a **a**, con cui otteniamo `[10][0]` e infine il simbolo **t**, per ottenere `[10][0][1110]`, o `1001110`. Il risultato richiede soltanto **7 bit** per essere memorizzato, 3,4 volte volte in meno rispetto ai 24 bit iniziali.
|
||||
|
||||
È importante notare che ogni codice binario deve avere un prefisso unico (*proprietà del prefisso*). La [codifica di Huffman](https://it.wikipedia.org/wiki/Codifica_di_Huffman) aiuta a calcolare questi codici. Nonostante questa tecnica abbia qualche problema, ci sono ancora [alcuni codec video che la offrono](https://en.wikipedia.org/wiki/Context-adaptive_variable-length_coding) come opzione.
|
||||
|
||||
Sia il codificatore (encoder) che il decodificatore (decoder) **devono conoscere la tabella simboli-codici**, per cui è necessario salvare anche la tabella.
|
||||
|
||||
### Codifica aritmetica:
|
||||
|
||||
Supponiamo di avere il flusso di simboli **a**, **e**, **r**, **s** e **t**, le cui probabilità sono rappresentate dalla tabella.
|
||||
|
||||
| | a | e | r | s | t |
|
||||
|-------------|-----|-----|------|------|-----|
|
||||
| probabilità | 0,3 | 0,3 | 0,15 | 0,05 | 0,2 |
|
||||
|
||||
Usando le probabilità possiamo associare degli intervalli ai simboli, ordinandoli per probabilità decrescente.
|
||||
|
||||

|
||||
|
||||
Ora codifichiamo il flusso **eat**: prendiamo il primo simbolo **a**, il cui intervallo va **da 0,3 a 0,6** (non incluso). Lo dividiamo nuovamente, usando le stesse proporzioni della divisione originale, solo che applicate al sottointervallo.
|
||||
|
||||

|
||||
|
||||
Continuiamo con la codifica del flusso **eat**, prendendo il simbolo **a** che corrisponde ora all'intervallo che va **da 0,3 a 0,39**. Infine ripetiamo il processo con il simbolo **t**, ottenendo l'ultimo intervallo tra **0,354 e 0,372**.
|
||||
|
||||

|
||||
|
||||
Dobbiamo ora semplicemente prendere un qualsiasi valore contenuto tra **0,354 e 0,372**, ad esempio **0,36**, ma potremmo prenderne uno qualsiasi. Con **solo** questo numero siamo in grado di ricostruire il flusso di simboli originale **eat**. Se ci pensi, è come se stessimo tracciando una riga che attraversa gli intervalli e i sottointervalli per codificare il flusso.
|
||||
|
||||

|
||||
|
||||
Il **processo inverso** (la decodifica) è ugualmente facile. Avendo a disposizione il numero **0,36** e l'intervallo originale possiamo seguire la stessa procedura, usando il numero per scoprire sottointervallo per sottointervallo il flusso di simboli associato.
|
||||
|
||||
In pratica, usando il primo intervallo troviamo che il numero è compreso nell'intervallo del simbolo **e**, per cui prendiamo quell'intervallo e lo dividiamo di nuovo. Ripetiamo quanto appena fatto per trovare che il valore **0,36** è compreso nell'intervallo di **a**, che è quindi il secondo simbolo del flusso. Infine troviamo l'ultimo simbolo **t**, che va a completare il flusso finale **eat**.
|
||||
|
||||
Sia l'encoder che il decoder **devono conoscere** la tabella dei simboli con le probabilità, per cui la tabella deve essere salvata e trasmessa.
|
||||
|
||||
Interessante vero? Ci devono essere persone incredibilmente intelligenti per riuscire a inventare una soluzione del genere, che oggi viene usata [in molti codec video](https://en.wikipedia.org/wiki/Context-adaptive_binary_arithmetic_coding).
|
||||
|
||||
L'idea che deve restare è che si può prendere il flusso di bit (bitstream) risultante dalla quantizzazione e comprimerlo in modo lossless, cioè senza perdita di informazioni. Sicuramente questo articolo manca di molti dettagli, spiegazioni, vantaggi e compromessi, ma puoi [imparare facilmente di più se sei uno sviluppatore](https://www.amazon.it/Understanding-Compression-Data-Modern-Developers/dp/1491961538/). I nuovi codec stanno iniziando ad usare differenti sistemi di codifica dell'entropia, [come ANS](https://en.wikipedia.org/wiki/Asymmetric_numeral_systems).
|
||||
|
||||
> ### Esercizio: CABAC vs CAVLC
|
||||
> Puoi [generare due video, uno con codifica dell'entropia CABAC e l'altro con CAVLC](https://github.com/leandromoreira/introduction_video_technology/blob/master/encoding_pratical_examples.md#cabac-vs-cavlc), e **confrontare il tempo di codifica**, così come la **dimensione del file finale**.
|
||||
|
||||
## 6° passo - formato bitstream
|
||||
|
||||
Dopo aver completato tutti questi passaggi, ora dobbiamo **compattare tutti i fotogrammi compressi con le loro informazioni di contesto**. Dobbiamo informare in modo esplicito il decoder delle **decisioni che sono state prese dall'encoder durante la codifica**, tra cui la profondità di bit, lo spazio colore, la risoluzione, le predizioni (vettori di moto inter-frame, direzione della predizione intra-frame), il profilo, il livello, il frame rate, il tipo di fotogramma, il numero di fotogramma e molto altro.
|
||||
|
||||
Stiamo per studiare, superficialmente, il bitstream del codec H.264. La prima cosa da fare è [generare un bitstream H.264 minimo<sup>\*</sup>](/encoding_pratical_examples.md#generate-a-single-frame-h264-bitstream), usando [ffmpeg](http://ffmpeg.org/).
|
||||
|
||||
```
|
||||
./s/ffmpeg -i /files/i/minimal.png -pix_fmt yuv420p /files/v/minimal_yuv420.h264
|
||||
```
|
||||
|
||||
> <sup>\*</sup>ffmpeg aggiunge, in modo predefinito, tutti i parametri di codifica come un **NAL SEI**. Presto definiremo che cos'è un NAL.
|
||||
|
||||
Il comando genera un bitstream H.264 "raw" (senza formato contenitore), con un **singolo fotogramma**, di dimensione 64x64 pixel, con spazio colore yuv420 (cioè YCbCr 4:2:0) e usando l'immagine seguente come fotogramma.
|
||||
|
||||
> 
|
||||
|
||||
### Bitstream di H.264
|
||||
|
||||
Lo standard AVC (H.264) stabilisce che le informazioni vengano trasmesse in **macro frame** (nel significato legato alle reti di telecomunicazioni), chiamati **[NAL](https://en.wikipedia.org/wiki/Network_Abstraction_Layer)** (Network Abstraction Layer). L'obiettivo principale dei NAL è fornire una rappresentazione del video che sia adatta per la trasmissione in rete, considerato che lo standard deve funzionare sulle tv (basate su flussi) e tramite Internet (basato su pacchetti), tra gli altri.
|
||||
|
||||

|
||||
|
||||
Viene usato un **[segnale di sincronizzazione](https://en.wikipedia.org/wiki/Frame_synchronization)** (*synchronization marker*) per delimitare le unità NAL. Ogni segnale di sincronizzazione corrisponde al valore fisso `0x00 0x00 0x01`, ad eccezione del primo che ha il valore `0x00 0x00 0x00 0x01`. Se eseguiamo il comando **hexdump** sul bitstream H.264 che abbiamo generato, riusciamo facilmente ad identificare almeno tre unità NAL all'inizio del file.
|
||||
|
||||

|
||||
|
||||
Come detto prima, il decodificatore ha bisogno non solo dei dati dell'immagine, ma anche di dettagli come il numero di fotogramma, i colori, i parametri usati e altro. Il **primo byte** di ciascun NAL definisce la sua categoria e il **tipo**.
|
||||
|
||||
| ID del tipo di NAL | Descrizione |
|
||||
|--- |---|
|
||||
| 0 | Non definito |
|
||||
| 1 | Slice codificato di un'immagine non IDR |
|
||||
| 2 | Slice codificato di una partizione A |
|
||||
| 3 | Slice codificato di una partizione B |
|
||||
| 4 | Slice codificato di una partizione C |
|
||||
| 5 | **IDR** Slice codificato di un'immagine IDR |
|
||||
| 6 | **SEI** Informazioni aggiuntive (*supplemental enhancement information*) |
|
||||
| 7 | **SPS** Insieme parametri di sequenza (*sequence parameter set*) |
|
||||
| 8 | **PPS** Insieme parametri d'immagine (*picture parameter set*) |
|
||||
| 9 | Delimitatore di unità di accesso |
|
||||
| 10 | Fine della sequenza |
|
||||
| 11 | Fine del flusso |
|
||||
| ... | ... |
|
||||
|
||||
Solitamente il primo NAL di un bitstream è di tipo **SPS**. Questo tipo di NAL contiene informazioni generiche sulle variabili di codifica, come il **profilo**, il **livello**, la **risoluzione** e altro.
|
||||
|
||||
Se saltiamo il primo segnale di sincronizzazione possiamo decodificare il **primo byte** per capire il **tipo del primo NAL** del bitstream di esempio.
|
||||
|
||||
Ad esempio in questo caso il primo byte dopo la sincronizzazione è `01100111`, dove il primo bit (`0`) si riferisce al campo **forbidden_zero_bit**, i due bit successivi (`11`) indicano il campo **nal_ref_idc**, che stabilisce se il NAL è un campo di riferimento oppure no, e infine gli ultimi cinque bit (`00111`) sono il campo **nal_unit_type**, cioè il tipo di NAL, in questo caso **SPS** (7).
|
||||
|
||||
Il secondo byte (`bin=01100100, hex=0x64, dec=100`) di un NAL SPS è il campo **profile_idc**, che indica il profilo che è stato usato per la codifica. In questo esempio è stato usato il profilo ["Constrained High"](https://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Profiles), che è un profilo "alto" senza il supporto agli slice di tipo B (bi-predittive).
|
||||
|
||||

|
||||
|
||||
Se leggiamo le specifiche del bitstream H.264 troveremo diversi valori per i campi **nome parametro**, **categoria** e **descrizione**. Ad esempio consideriamo i campi `pic_width_in_mbs_minus_1` e `pic_height_in_map_units_minus_1`.
|
||||
|
||||
| Nome parametro | Categoria | Descrizione |
|
||||
|--- |---|---|
|
||||
| pic_width_in_mbs_minus_1 | 0 | ue(v) |
|
||||
| pic_height_in_map_units_minus_1 | 0 | ue(v) |
|
||||
|
||||
> **ue(v)**: intero senza segno [codificato con Exp-Golomb](https://pythonhosted.org/bitstring/exp-golomb.html)
|
||||
|
||||
Facendo un po' di calcoli possiamo utilizzare il valore di questi campi per ricavare la **risoluzione**. Ad esempio una risoluzione di `1920 x 1080` può essere ottenuta dando al parametro `pic_width_in_mbs_minus_1` il valore di `119 ( (119 + 1) * dimensione_macroblocco = 120 * 16 = 1920)`. Abbiamo risparmiato spazio, memorizzando `119` anziché `1920`.
|
||||
|
||||
Se continuiamo a esaminare il video creato con un visualizzatore binario (es. `xxd -b -c 11 v/minimal_yuv420.h264`), possiamo saltare all'ultimo NAL che è il fotogramma vero e proprio.
|
||||
|
||||

|
||||
|
||||
Il valore dei primi 6 byte è `01100101 10001000 10000100 00000000 00100001 11111111`. Come abbiamo visto dal primo byte si può ricavare il tipo di NAL, in questo caso `00101`, che corrisponde a **Slice IDR (5)**. Continuiamo con l'ispezione.
|
||||
|
||||

|
||||
|
||||
Utilizzando le specifiche dell'header degli slice H.264 possiamo decodificare il tipo di slice (**slice_type**), il numero del fotogramma (**frame_num**), assieme ad altre importanti informazioni.
|
||||
|
||||
Per ottenere il reale valore di alcuni campi (`ue(v), me(v), se(v), te(v)`) dobbiamo decodificarli utilizzando un metodo speciale chiamato [Exponential-Golomb](https://pythonhosted.org/bitstring/exp-golomb.html), che è un **modo molto efficiente per codificare valori variabili**, specialmente quando vengono usati molti valori predefiniti.
|
||||
|
||||
> I valori **slice_type** e **frame_num** sono 7 (slice di tipo I) e 0 (primo fotogramma).
|
||||
|
||||
Possiamo vedere il **bitstream come un protocollo**, e se vuoi o devi imparare di più a proposito del bitstream fai riferimento alle [specifiche H.264 dell'ITU](http://www.itu.int/rec/T-REC-H.264-201610-I). Ecco un diagramma semplificato che mostra dove vengono memorizzati i dati dell'immagine vera e propria (YCbCr/YUV compresso).
|
||||
|
||||

|
||||
|
||||
Possiamo esplorare altri bitstream come [quello di VP9](https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf), [H.265 (HEVC)](http://handle.itu.int/11.1002/1000/11885-en?locatt=format:pdf) o anche il nostro **nuovo miglior amico** [**AV1**](https://medium.com/@mbebenita/av1-bitstream-analyzer-d25f1c27072b#.d5a89oxz8
|
||||
). Si assomigliano? [No, ma una volta imparato uno capire gli altri è facile](http://www.gpac-licensing.com/2016/07/12/vp9-av1-bitstream-format/).
|
||||
|
||||
> ### Esercizio: ispezionare il bitstream H.264
|
||||
> Possiamo [generare un video con un singolo fotogramma](https://github.com/leandromoreira/introduction_video_technology/blob/master/encoding_pratical_examples.md#generate-a-single-frame-video) e usare [mediainfo](https://en.wikipedia.org/wiki/MediaInfo) per ispezionare il suo bitstream H.264. Infatti puoi anche vedere il [codice sorgente che si occupa del parsing del bitstream H.264 (AVC)](https://github.com/MediaArea/MediaInfoLib/blob/master/Source/MediaInfo/Video/File_Avc.cpp).
|
||||
>
|
||||
> 
|
||||
>
|
||||
> In alternativa possiamo usare il software [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (è a pagamento ma esiste una versione di prova che limita l'analisi ai primi 10 fotogrammi).
|
||||
>
|
||||
> 
|
||||
|
||||
## Ripasso
|
||||
|
||||
Molti dei **codec moderni utilizzano lo stesso modello di codifica che abbiamo imparato**. Ad esempio, diamo un'occhiata al diagramma a blocchi del codec video Thor, che contiene tutti i passi che abbiamo studiato. A questo punto dovresti essere in grado almeno di comprendere meglio le innovazioni e gli articoli che riguardano questi argomenti.
|
||||
|
||||

|
||||
|
||||
Inizialmente abbiamo calcolato che ci servono [139 GB di spazio per archiviare un file di un'ora nel formato 720p30](#sottocampionamento-della-crominanza). Se applichiamo le tecniche imparate qui, come **la predizione intra-frame e inter-frame, la trasformata, la quantizzazione, la codifica dell'entropia**, assumendo che spendiamo **0,031 bit per pixel** possiamo raggiungere la stessa qualità percepita utilizzando soltanto **368 MB anziché 139 GB**.
|
||||
|
||||
> Abbiamo scelto di usare **0,031 bit per pixel** basandoci sull'esempio precedente.
|
||||
|
||||
## Come fa H.265 a comprimere più di H.264?
|
||||
|
||||
Ora che sappiamo come funziona un codec, risulta più facile capire come i nuovi codec sono in grado di memorizzare risoluzioni più alte usando meno bit.
|
||||
|
||||
Confronteremo AVC e HEVC, tenendo in mente che il processo è quasi sempre un compromesso tra la complessità dell'algoritmo (cicli di CPU) e il tasso di compressione.
|
||||
|
||||
HEVC ha **partizioni** (e **sottopartizioni**) più grandi e più numerose rispetto ad AVC, inoltre ha **più direzioni di predizione intra-frame**, una **migliore codifica dell'entropia**, e altro. Tutto insieme fa in modo che H.265 sia in grado di comprimere il 50% in più rispetto ad H.264.
|
||||
|
||||

|
||||
|
||||
# Streaming online
|
||||
## Architettura generale
|
||||
|
||||

|
||||
|
||||
[TODO]
|
||||
|
||||
## Download progressivo vs streaming adattivo
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
[TODO]
|
||||
|
||||
## Protezione dei contenuti
|
||||
|
||||
Possiamo usare un semplice **sistema a token** (gettone) per proteggere i contenuti. Un utente senza token che prova a richiedere un video viene bloccato dalla CDN, mentre un utente con un token valido può riprodurre il contenuto. Funziona in modo abbastanza simile alla maggior parte dei sistemi di autenticazione sul web.
|
||||
|
||||

|
||||
|
||||
L'utilizzo di questo sistema consente comunque all'utente di scaricare e ridistribuire il video. Un sistema **DRM (digital rights management)** permette di evitare anche questo problema.
|
||||
|
||||

|
||||
|
||||
I sistemi di produzione nel mondo reale in genere usano entrambe le tecniche, per offrire sia autorizzazione che autenticazione.
|
||||
|
||||
### DRM
|
||||
#### Sistemi principali
|
||||
|
||||
* FPS - [**FairPlay Streaming**](https://developer.apple.com/streaming/fps/)
|
||||
* PR - [**PlayReady**](https://www.microsoft.com/playready/)
|
||||
* WV - [**Widevine**](http://www.widevine.com/)
|
||||
|
||||
|
||||
#### Cos'è?
|
||||
|
||||
DRM sta per *gestione dei diritti digitali* (*Digital Rights Management*) ed è un modo per **aggiungere una protezione del diritto d'autore ai contenuti digitali**, quindi anche al video e all'audio. Nonostante sia molto usato, [non è universalmente accettato](https://en.wikipedia.org/wiki/Digital_rights_management#DRM-free_works).
|
||||
|
||||
#### Perché?
|
||||
|
||||
I creatori di contenuti (principalmente gli studi) vogliono proteggere la proprietà intellettuale dalla copia, per prevenire la ridistribuzione non autorizzata dei contenuti digitali.
|
||||
|
||||
#### Come?
|
||||
|
||||
Descriveremo un modello generico ed astratto di DRM in un modo molto semplificato.
|
||||
|
||||
Sia dato un **contenuto C1** (es. uno streaming video HLS o DASH), con un **player P1** (es. shaka-clappr, exo-player o iOS) e un **dispositivo D1** (es. uno smartphone, una tv, un tablet o un computer), che utilizzano un **sistema DRM che chiamiamo DRM1** (es. Widevine, PlayReady, FairPlay).
|
||||
|
||||
Il contenuto C1 viene cifrato con una **chiave simmetrica K1** fornita dal sistema DRM1, così da ottenere il **contenuto cifrato C'1**.
|
||||
|
||||

|
||||
|
||||
Il player P1 del dispositivo D1 possiede due chiavi (asimmetriche), cioè una **chiave privata PRK1** (questa chiave è protetta<sup>1</sup> e conosciuta solo da **D1**) e una **chiave pubblica PUK1**.
|
||||
|
||||
> **<sup>1</sup>protetta**: questa protezione può essere ottenuta sia **tramite hardware**, memorizzando la chiave all'interno di un chip speciale in sola lettura che agisce come una [scatola nera](https://it.wikipedia.org/wiki/Modello_black_box) per fornire la decifratura, sia **tramite software** (in modo meno sicuro). Il sistema DRM offre dei modi per sapere quale tipo di protezione il dispositivo ha a disposizione.
|
||||
|
||||
Quando il **player P1 vuole riprodurre il contenuto C'1**, deve contrattare con il **sistema DRM1**, fornendogli la sua chiave pubblica **PUK1**. Il sistema DRM1 ritorna la **chiave K1 cifrata** con la chiave pubblica **PUK1** del client. A livello teorico, questa risposta è qualcosa che **soltanto D1 è in grado di decifrare**.
|
||||
|
||||
`K1P1D1 = enc(K1, PUK1)`
|
||||
|
||||
Il player **P1** utilizza il suo sistema DRM locale (che potrebbe essere un [SoC](https://it.wikipedia.org/wiki/System-on-a-chip), una parte di software o hardware specializzata), **in grado di decifrare** il contenuto utilizzando la sua chiave privata PRK1. In questo modo può **decifrare la chiave simmetrica K1 da K1P1D1** e quindi riprodurre **C'1**. Nel migliore dei casi, le chiavi non sono esposte nella memoria RAM.
|
||||
|
||||
```
|
||||
K1 = dec(K1P1D1, PRK1)
|
||||
|
||||
P1.play(dec(C'1, K1))
|
||||
```
|
||||
|
||||

|
||||
|
||||
# Come usare jupyter
|
||||
|
||||
Assicurati di avere **Docker installato** e avvia `./s/start_jupyter.sh`. Segui poi le istruzioni mostrate nel terminale.
|
||||
|
||||
# Conferenze
|
||||
|
||||
* [DEMUXED](https://demuxed.com/) - puoi [guardare le presentazioni degli ultimi 2 eventi](https://www.youtube.com/channel/UCIc_DkRxo9UgUSTvWVNCmpA).
|
||||
|
||||
# Riferimenti
|
||||
|
||||
Il contenuto più ricco è qua, puoi trovare le informazioni che hanno ispirato questo testo e da cui sono stati estratti i concetti. Puoi approfondire la tua conoscenza leggendo questi link, libri, video, ecc.
|
||||
|
||||
Corsi online e tutorial:
|
||||
|
||||
* https://www.coursera.org/learn/digital/
|
||||
* https://people.xiph.org/~tterribe/pubs/lca2012/auckland/intro_to_video1.pdf
|
||||
* https://xiph.org/video/vid1.shtml
|
||||
* https://xiph.org/video/vid2.shtml
|
||||
* http://slhck.info/ffmpeg-encoding-course
|
||||
* http://www.cambridgeincolour.com/tutorials/camera-sensors.htm
|
||||
* http://www.slideshare.net/vcodex/a-short-history-of-video-coding
|
||||
* http://www.slideshare.net/vcodex/introduction-to-video-compression-13394338
|
||||
* https://developer.android.com/guide/topics/media/media-formats.html
|
||||
* http://www.slideshare.net/MadhawaKasun/audio-compression-23398426
|
||||
* http://inst.eecs.berkeley.edu/~ee290t/sp04/lectures/02-Motion_Compensation_girod.pdf
|
||||
|
||||
Libri:
|
||||
|
||||
* https://www.amazon.com/Understanding-Compression-Data-Modern-Developers/dp/1491961538/ref=sr_1_1?s=books&ie=UTF8&qid=1486395327&sr=1-1
|
||||
* https://www.amazon.com/H-264-Advanced-Video-Compression-Standard/dp/0470516925
|
||||
* https://www.amazon.com/Practical-Guide-Video-Audio-Compression/dp/0240806301/ref=sr_1_3?s=books&ie=UTF8&qid=1486396914&sr=1-3&keywords=A+PRACTICAL+GUIDE+TO+VIDEO+AUDIO
|
||||
* https://www.amazon.com/Video-Encoding-Numbers-Eliminate-Guesswork/dp/0998453005/ref=sr_1_1?s=books&ie=UTF8&qid=1486396940&sr=1-1&keywords=jan+ozer
|
||||
|
||||
Specifiche bitstream:
|
||||
|
||||
* http://www.itu.int/rec/T-REC-H.264-201610-I
|
||||
* http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=12904&lang=en
|
||||
* https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf
|
||||
* http://iphome.hhi.de/wiegand/assets/pdfs/2012_12_IEEE-HEVC-Overview.pdf
|
||||
* http://phenix.int-evry.fr/jct/doc_end_user/current_document.php?id=7243
|
||||
* http://gentlelogic.blogspot.com.br/2011/11/exploring-h264-part-2-h264-bitstream.html
|
||||
* https://forum.doom9.org/showthread.php?t=167081
|
||||
* https://forum.doom9.org/showthread.php?t=168947
|
||||
|
||||
Software:
|
||||
|
||||
* https://ffmpeg.org/
|
||||
* https://ffmpeg.org/ffmpeg-all.html
|
||||
* https://ffmpeg.org/ffprobe.html
|
||||
* https://trac.ffmpeg.org/wiki/
|
||||
* https://software.intel.com/en-us/intel-video-pro-analyzer
|
||||
* https://medium.com/@mbebenita/av1-bitstream-analyzer-d25f1c27072b#.d5a89oxz8
|
||||
|
||||
Codec non ITU:
|
||||
|
||||
* https://aomedia.googlesource.com/
|
||||
* https://github.com/webmproject/libvpx/tree/master/vp9
|
||||
* https://people.xiph.org/~xiphmont/demo/daala/demo1.shtml
|
||||
* https://people.xiph.org/~jm/daala/revisiting/
|
||||
* https://www.youtube.com/watch?v=lzPaldsmJbk
|
||||
* https://fosdem.org/2017/schedule/event/om_av1/
|
||||
|
||||
Concetti di codifica:
|
||||
|
||||
* http://x265.org/hevc-h265/
|
||||
* http://slhck.info/video/2017/03/01/rate-control.html
|
||||
* http://slhck.info/video/2017/02/24/vbr-settings.html
|
||||
* http://slhck.info/video/2017/02/24/crf-guide.html
|
||||
* https://arxiv.org/pdf/1702.00817v1.pdf
|
||||
* https://trac.ffmpeg.org/wiki/Debug/MacroblocksAndMotionVectors
|
||||
* http://web.ece.ucdavis.edu/cerl/ReliableJPEG/Cung/jpeg.html
|
||||
* http://www.adobe.com/devnet/adobe-media-server/articles/h264_encoding.html
|
||||
* https://prezi.com/8m7thtvl4ywr/mp3-and-aac-explained/
|
||||
* https://blogs.gnome.org/rbultje/2016/12/13/overview-of-the-vp9-video-codec/
|
||||
|
||||
Sequenze video per i test:
|
||||
|
||||
* http://bbb3d.renderfarming.net/download.html
|
||||
* https://www.its.bldrdoc.gov/vqeg/video-datasets-and-organizations.aspx
|
||||
|
||||
Varie:
|
||||
|
||||
* http://stackoverflow.com/a/24890903
|
||||
* http://stackoverflow.com/questions/38094302/how-to-understand-header-of-h264
|
||||
* http://techblog.netflix.com/2016/08/a-large-scale-comparison-of-x264-x265.html
|
||||
* http://vanseodesign.com/web-design/color-luminance/
|
||||
* http://www.biologymad.com/nervoussystem/eyenotes.htm
|
||||
* http://www.compression.ru/video/codec_comparison/h264_2012/mpeg4_avc_h264_video_codecs_comparison.pdf
|
||||
* http://www.csc.villanova.edu/~rschumey/csc4800/dct.html
|
||||
* http://www.explainthatstuff.com/digitalcameras.html
|
||||
* http://www.hkvstar.com
|
||||
* http://www.hometheatersound.com/
|
||||
* http://www.lighterra.com/papers/videoencodingh264/
|
||||
* http://www.red.com/learn/red-101/video-chroma-subsampling
|
||||
* http://www.slideshare.net/ManoharKuse/hevc-intra-coding
|
||||
* http://www.slideshare.net/mwalendo/h264vs-hevc
|
||||
* http://www.slideshare.net/rvarun7777/final-seminar-46117193
|
||||
* http://www.springer.com/cda/content/document/cda_downloaddocument/9783642147029-c1.pdf
|
||||
* http://www.streamingmedia.com/Articles/Editorial/Featured-Articles/A-Progress-Report-The-Alliance-for-Open-Media-and-the-AV1-Codec-110383.aspx
|
||||
* http://www.streamingmediaglobal.com/Articles/ReadArticle.aspx?ArticleID=116505&PageNum=1
|
||||
* http://yumichan.net/video-processing/video-compression/introduction-to-h264-nal-unit/
|
||||
* https://cardinalpeak.com/blog/the-h-264-sequence-parameter-set/
|
||||
* https://cardinalpeak.com/blog/worlds-smallest-h-264-encoder/
|
||||
* https://codesequoia.wordpress.com/category/video/
|
||||
* https://developer.apple.com/library/content/technotes/tn2224/_index.html
|
||||
* https://en.wikibooks.org/wiki/MeGUI/x264_Settings
|
||||
* https://en.wikipedia.org/wiki/Adaptive_bitrate_streaming
|
||||
* https://en.wikipedia.org/wiki/AOMedia_Video_1
|
||||
* https://en.wikipedia.org/wiki/Chroma_subsampling#/media/File:Colorcomp.jpg
|
||||
* https://en.wikipedia.org/wiki/Cone_cell
|
||||
* https://en.wikipedia.org/wiki/File:H.264_block_diagram_with_quality_score.jpg
|
||||
* https://en.wikipedia.org/wiki/Inter_frame
|
||||
* https://en.wikipedia.org/wiki/Intra-frame_coding
|
||||
* https://en.wikipedia.org/wiki/Photoreceptor_cell
|
||||
* https://en.wikipedia.org/wiki/Pixel_aspect_ratio
|
||||
* https://en.wikipedia.org/wiki/Presentation_timestamp
|
||||
* https://en.wikipedia.org/wiki/Rod_cell
|
||||
* https://it.wikipedia.org/wiki/File:Pixel_geometry_01_Pengo.jpg
|
||||
* https://leandromoreira.com.br/2016/10/09/how-to-measure-video-quality-perception/
|
||||
* https://sites.google.com/site/linuxencoding/x264-ffmpeg-mapping
|
||||
* https://softwaredevelopmentperestroika.wordpress.com/2014/02/11/image-processing-with-python-numpy-scipy-image-convolution/
|
||||
* https://tools.ietf.org/html/draft-fuldseth-netvc-thor-03
|
||||
* https://www.encoding.com/android/
|
||||
* https://www.encoding.com/http-live-streaming-hls/
|
||||
* https://web.archive.org/web/20150129171151/https://www.iem.thm.de/telekom-labor/zinke/mk/mpeg2beg/whatisit.htm
|
||||
* https://www.lifewire.com/cmos-image-sensor-493271
|
||||
* https://www.linkedin.com/pulse/brief-history-video-codecs-yoav-nativ
|
||||
* https://www.linkedin.com/pulse/video-streaming-methodology-reema-majumdar
|
||||
* https://www.vcodex.com/h264avc-intra-precition/
|
||||
* https://www.youtube.com/watch?v=9vgtJJ2wwMA
|
||||
* https://www.youtube.com/watch?v=LFXN9PiOGtY
|
||||
* https://www.youtube.com/watch?v=Lto-ajuqW3w&list=PLzH6n4zXuckpKAj1_88VS-8Z6yn9zX_P6
|
||||
* https://www.youtube.com/watch?v=LWxu4rkZBLw
|
||||
* https://web.stanford.edu/class/ee398a/handouts/lectures/EE398a_MotionEstimation_2012.pdf
|
||||
+924
@@ -0,0 +1,924 @@
|
||||
[](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)
|
||||
|
||||
# はじめに
|
||||
|
||||
ビデオ技術のやさしい入門書です。ソフトウェア開発者/エンジニア向けですが、**誰でも理解できるように**やさしく説明したいと思っています。 [ビデオ技術初心者のためのミニワークショップ](https://docs.google.com/presentation/d/17Z31kEkl_NGJ0M66reqr9_uTG6tI5EDDVXpdPKVuIrs/edit#slide=id.p)からこのアイディアが生まれました。
|
||||
|
||||
できるだけ**簡潔な言葉、たくさんの視覚的要素、具体的な例**を使っていくつかのデジタルビデオの概念を紹介し、誰でもこの知識が得られる機会を提供することが目標です。どうかご自由に訂正や提案を送り、改善してみてください。
|
||||
|
||||
いくつかの**ハンズオン**セクションでは**dockerがインストール済み**で、このレポジトリがクローンされている必要があります。
|
||||
|
||||
```bash
|
||||
git clone https://github.com/leandromoreira/digital_video_introduction.git
|
||||
cd digital_video_introduction
|
||||
./setup.sh
|
||||
```
|
||||
> **注意**: `./s/ffmpeg` や `./s/mediainfo` コマンドは、そのプログラムが**Dockerコンテナ上**で実行されることを意味しています。コンテナの中には、すでに必要な依存関係が全て含まれています。
|
||||
|
||||
全ての**ハンズオンはこのレポジトリをクローンしたフォルダで実行してください**。 **jupyter examples**については、`./s/start_jupyter.sh`でサーバーを起動して、表示されるURLをブラウザで開いてください。
|
||||
|
||||
# 変更履歴
|
||||
|
||||
* DRMシステムの追加
|
||||
* 1.0.0版のリリース
|
||||
* 簡体字訳の追加
|
||||
|
||||
# 目次
|
||||
|
||||
- [はじめに](#はじめに)
|
||||
- [目次](#目次)
|
||||
- [基本用語](#基本用語)
|
||||
* [カラー画像を符号化する別の方法](#カラー画像を符号化する別の方法)
|
||||
* [ハンズオン: 画像と色の実験](#ハンズオン-画像と色の実験)
|
||||
* [DVDの画面アスペクト比は4:3](#dvdの画面アスペクト比は43)
|
||||
* [ハンズオン: ビデオプロパティを調べる](#ハンズオン-ビデオプロパティを調べる)
|
||||
- [冗長性除去](#冗長性除去)
|
||||
* [色、明るさと私たちの目](#色、明るさと私たちの目)
|
||||
+ [カラーモデル](#カラーモデル)
|
||||
+ [YCbCrとRGB間の変換](#ycbcrとrgb間の変換)
|
||||
+ [クロマサブサンプリング](#クロマサブサンプリング)
|
||||
+ [ハンズオン: YCbCrヒストグラムを調べる](#ハンズオン-ycbcrヒストグラムを調べる)
|
||||
* [フレームの種類](#フレームの種類)
|
||||
+ [Iフレーム (イントラ、キーフレーム)](#iフレーム-イントラ、キーフレーム)
|
||||
+ [Pフレーム (予測)](#pフレーム-予測)
|
||||
- [ハンズオン: Iフレームが1つだけのビデオ](#ハンズオン-iフレームが1つだけのビデオ)
|
||||
+ [Bフレーム (双方向予測)](#bフレーム-双方向予測)
|
||||
- [ハンズオン: Bフレーム付きのビデオとの比較](#ハンズオン-bフレーム付きのビデオとの比較)
|
||||
+ [まとめ](#まとめ)
|
||||
* [時間的冗長性 (インター予測)](#時間的冗長性-インター予測)
|
||||
- [ハンズオン: 動きベクトルを見る](#ハンズオン-動きベクトルを見る)
|
||||
* [空間的冗長性 (イントラ予測)](#空間的冗長性-イントラ予測)
|
||||
- [ハンズオン: イントラ予測を調べる](#ハンズオン-イントラ予測を調べる)
|
||||
- [ビデオコーデックの仕組み](#ビデオコーデックの仕組み)
|
||||
* [何か? なぜ? どのように?](#何か-なぜ-どのように)
|
||||
* [歴史](#歴史)
|
||||
+ [AV1の誕生](#av1の誕生)
|
||||
* [一般的コーデック](#一般的コーデック)
|
||||
* [ステップ1 - 画像分割](#ステップ1---画像分割)
|
||||
+ [ハンズオン: パーティションを調べる](#ハンズオン-パーティションを調べる)
|
||||
* [ステップ2 - 予測](#ステップ2---予測)
|
||||
* [ステップ3 - 変換](#ステップ3---変換)
|
||||
+ [ハンズオン: 種々の係数を捨てる](#ハンズオン-種々の係数を捨てる)
|
||||
* [ステップ4 - 量子化](#ステップ4---量子化)
|
||||
+ [ハンズオン: 量子化](#ハンズオン-量子化)
|
||||
* [ステップ5 - エントロピー符号化](#ステップ5---エントロピー符号化)
|
||||
+ [可変長符号](#可変長符号)
|
||||
+ [算術符号](#算術符号)
|
||||
+ [ハンズオン: CABAC対CAVLC](#ハンズオン-cabac対cavlc)
|
||||
* [ステップ6 - ビットストリームフォーマット](#ステップ6---ビットストリームフォーマット)
|
||||
+ [H.264ビットストリーム](#h264ビットストリーム)
|
||||
+ [ハンズオン: H.264ビットストリームを調べる](#ハンズオン-h264ビットストリームを調べる)
|
||||
* [おさらい](#おさらい)
|
||||
* [どのようにH.265はH.264よりも良い圧縮率を実現しているのか?](#どのようにh265はh264よりも良い圧縮率を実現しているのか)
|
||||
- [オンラインストリーミング](#オンラインストリーミング)
|
||||
* [一般的なアーキテクチャ](#一般的なアーキテクチャ)
|
||||
* [プログレッシブダウンロードとアダプティブストリーミング](#プログレッシブダウンロードとアダプティブストリーミング)
|
||||
* [コンテンツ保護](#コンテンツ保護)
|
||||
- [jupyterの使い方](#jupyterの使い方)
|
||||
- [カンファレンス](#カンファレンス)
|
||||
- [参考文献](#参考文献)
|
||||
|
||||
# 基本用語
|
||||
|
||||
**画像**は**二次元マトリクス**として考えることができます。**色**を考慮すると、画像を**色のデータ**を表すための**もう一つの次元**を持った**三次元マトリクス**として捉えることができます。
|
||||
|
||||
これらの色を[原色 (赤、緑、青)](https://ja.wikipedia.org/wiki/%E5%8E%9F%E8%89%B2)で表現すると、三つの平面を定義することになります。一つめが**赤**、二つ目が**緑**そして三つ目が**青**です。
|
||||
|
||||

|
||||
|
||||
マトリクスのそれぞれの要素を**ピクセル** (画素)と呼びます。一つのピクセルはその色の**輝度** (通常は数値)を表します。例えば、**赤ピクセル**は緑が0、青が0、赤が最大を意味します。**ピンク色ピクセル**もこれら三つの値で表現できます。0から255の数値で表現することにより、ピンクピクセルは**赤=255、緑=192、青=203**と定義されます。
|
||||
|
||||
> #### カラー画像を符号化する別の方法
|
||||
> 画像を形成する色を表現するためには、他にも多くのモデルが使えます。例えば、色を表現するのにRGBモデルでは3バイト使うのに対して、1バイトしか使わないインデックスパレットを使うことができます。そういったモデルでは、色を表現するために三次元モデルを使わずに二次元モデルを使用できるできるでしょう。メモリを節約できますが、色の選択肢を狭めることになります。
|
||||
>
|
||||
> 
|
||||
|
||||
例えば、下の画像をみてください。最初の顔は全ての色を使っています。他の写真は赤、緑、青の平面です。 (グレートーンで示しています).
|
||||
|
||||

|
||||
|
||||
**赤色**が最終的な色に対して**より貢献している** (二番目の顔の最も明るい部分)ことが分かります。一方**青色** の貢献は服の一部と**マリオの目にしかみられません**(最後の顔) 。**マリオのひげ**に対しては、**全ての平面があまり貢献していない**(最も暗い部分)ことが分かります。
|
||||
|
||||
各色の輝度では**ビット深度**として知られる一定量のビットが不可欠です。色(平面)ごとに(0から255の値で表現する)**8ビット**を使うとすると、**24 (8 X 3)ビット**の**色深度**を持つことになり、2の24乗種類の色を使えることが推論できます。
|
||||
|
||||
> [画像がどのように万物をビットとしてとらえるのか](http://www.cambridgeincolour.com/tutorials/camera-sensors.htm)を学ぶと **良い**でしょう
|
||||
|
||||
もう一つの画像のプロパティは **解像度**です。解像度は長さあたりのピクセルの数です。解像度はよく幅 x 高さとして表現されます。例えば、下記は**4×4**の画像です。
|
||||
|
||||

|
||||
|
||||
> #### ハンズオン: 画像と色の実験
|
||||
> [jupyter](#jupyterの使い方) (python、numpy、matplotlib、その他)を使って、[画像と色の実験](/image_as_3d_array.ipynb)をしましょう。
|
||||
>
|
||||
> [(エッジ検出, シャープ化, ぼかし等の)画像フィルタがどのように動くか](/filters_are_easy.ipynb)を学びましょう。
|
||||
|
||||
画像やビデオの作業をする時にみるもう一つのプロパティは **アスペクト比**です。アスペクト比は、画像やピクセルの幅と高さの比率を表します。
|
||||
|
||||
動画や画像が**16x9**であると言うときは、たいてい**画面アスペクト比 (DAR)** のことを指します。しかし、個々のピクセルを様々な形状にすることができ、これを **ピクセルアスペクト比 (PAR)** といいます。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
> #### DVDの画面アスペクト比は4:3
|
||||
> DVDの実際の解像度は704x480ですが、10:11のピクセルアスペクト比を持っているため、4:3のアスペクト比を保っています。(704x10/480x11)
|
||||
|
||||
最後に、**ビデオ**を**単位時間**内の***n*フレームの並び**として定義でき、もう一つの特性と見ることができます。*n*はフレームレートもしくは秒間フレーム数 (FPS)です。
|
||||
|
||||

|
||||
|
||||
ビデオを表すために必要な秒間あたりのビット数は**ビットレート**です。
|
||||
|
||||
> ビットレート = 幅 x 高さ x ビット深度 x フレームレート
|
||||
|
||||
例えば、圧縮を全く使わないなら、フレームレートが30で、ピクセルあたりが24ビットで、解像度が480x240のビデオは、**秒間あたり82,944,000ビット**もしくは82.944 Mbps (30x480x240x24)が必要です。
|
||||
|
||||
**ビットレート**がほとんど一定なら、固定ビットレート(**CBR**)と呼ばれます。ビットレートが変動するなら、可変ビットレート (**VBR**)と呼ばれます。
|
||||
|
||||
> このグラフはフレームが真っ黒の間はあまりビットを使わない、制約付きのVBRを示しています。
|
||||
>
|
||||
> 
|
||||
|
||||
黎明期に、技術者たちが**帯域幅を増やさずに**ビデオ画面で認識できるフレームレートを倍にする技術を思いつきました。この技術は**インターレース動画**として知られています。基本的には一つ目の「フレーム」で画面の半分を送り、次の「フレーム」で残りの半分を送ります。
|
||||
|
||||
今日では **プログレッシブスキャン技術**を使って画面に描画されます。プログレッシブは、動画を描画、保存、転送する手段の一つで、各フレームの全走査線を順番に描画します。
|
||||
|
||||

|
||||
|
||||
これで**画像**がどのようにデジタル表現されるのかが分かりました。**色**がどのように配置され、ビデオを表すのにどのくらいの**秒間あたりのビット**が必要なのか、それが固定なのか(CBR)可変なのか(VBR)、**解像度**と**フレームレート**、他にもインターレースやピクセルアスペクト比、その他のたくさんの用語を学びました。
|
||||
|
||||
> #### ハンズオン: ビデオプロパティを調べる
|
||||
> [ffmpegやmediainfoを使って説明したプロパティのほとんどを調べる](https://github.com/leandromoreira/introduction_video_technology/blob/master/encoding_pratical_examples.md#inspect-stream)ことができます。
|
||||
|
||||
# 冗長性除去
|
||||
|
||||
圧縮なしにビデオを扱うことは不可能であることを学びました。解像度が720pで30fpsの場合、**1時間のビデオ一つ**に**278GB<sup>*</sup>が必要**です。(PKZIP、Gzip、PNGで使われている)DEFLATE のような**可逆圧縮アルゴリズム一つを使うだけでは**必要な帯域幅を十分に削減**できない**ため、ビデオを圧縮する別の方法を見つける必要があるのです。
|
||||
|
||||
> <sup>*</sup> この数値は1280 x 720 x 24 x 30 x 3600 (幅、高さ、ピクセルあたりのビット数、フレームレート、秒単位での時間)を掛けることで算出しました
|
||||
|
||||
これを成し遂げるために、**私たちの視覚の仕組みを利用する**ことができます。私たちは色よりも明るさを見分けることが得意です。また、ビデオには少しの変化しかない多くの画像が含まれている**時間的繰り返し**があります。それぞれのフレームもまた、多くの領域では同じか似ている色が使われている**画像内の繰り返し**があります。
|
||||
|
||||
## 色、明るさと私たちの目
|
||||
|
||||
私たちの目は[色よりも明るさにより敏感](http://vanseodesign.com/web-design/color-luminance/)です。この画像をみてそれを自分自身で確認できます。
|
||||
|
||||

|
||||
|
||||
左側の**正方形Aと正方形B**の色は**同じ**であることが分からないとしても大丈夫です。私たちの脳は**色よりも明暗に注意をはらう**ことで錯覚を起こさせているのです。右側では、同じ色のコネクターがあるため、私たち(私たちの脳)は、それらは実際は同じ色であるということを簡単に気づきます。
|
||||
|
||||
> **私たちの目がどのように機能するかの簡単な説明**
|
||||
>
|
||||
> [眼は複雑な器官](http://www.biologymad.com/nervoussystem/eyenotes.htm)で、たくさんのパーツから成り立っていますが、主に錐体細胞と桿体細胞に関心があります。眼は [1億2000万の桿体細胞と600万の錐体細胞を含んでいる](https://en.wikipedia.org/wiki/Photoreceptor_cell)のです。
|
||||
>
|
||||
> **ものすごく簡単にする**ため、眼のパーツの機能のうち色と明るさに焦点を当てましょう。**[桿体細胞](https://en.wikipedia.org/wiki/Rod_cell)は主に明るさに対して責任を持っています**。一方 **[錐体細胞](https://en.wikipedia.org/wiki/Cone_cell)は色に対して責任を持っています**。異なった色素を持つ3種類の錐体があり、名前は[S錐体(青)、M錐体(緑)、L錐体(赤)](https://upload.wikimedia.org/wikipedia/commons/1/1e/Cones_SMJ2_E.svg)です。
|
||||
>
|
||||
> 私たちは錐体細胞(色)よりも多くの桿体細胞(明るさ)を持っているため、色よりも明暗をより識別することができることが推論できます。
|
||||
>
|
||||
> 
|
||||
|
||||
私たちは**輝度**(画像の明るさの度合い)により敏感であることが分かりました。この特性を利用しましょう。
|
||||
|
||||
### カラーモデル
|
||||
|
||||
**RGBモデル**を使って[カラー画像がどのように](#basic-terminology)機能するのか最初に学びましたが、他のモデルも存在します。実は、輝度(明るさ)と色度(色)を別にするモデルが存在します。それは**YCbCr**<sup>*</sup>として知られています。
|
||||
|
||||
> <sup>*</sup> 同じ分離を行うモデルはもっと存在します。
|
||||
|
||||
このカラーモデルは明るさを表すために**Y**を使い、2つの色チャンネル**Cb** (青の色差)と**Cr** (赤の色差)を使います。[YCbCr](https://en.wikipedia.org/wiki/YCbCr)はRGBから生成することができ、RGBに戻すこともできます。下の写真のように、このモデルを使ってフルカラーの画像を作ることができます。
|
||||
|
||||

|
||||
|
||||
### YCbCrとRGB間の変換
|
||||
|
||||
中には **緑なしで色**の全てを生成できるのかと異議を唱える方もいるでしょう。
|
||||
|
||||
この質問に答えるために、RGBからYCbCrへの変換を一通り説明します。**[ITU-Rグループ<sup>*</sup>](https://en.wikipedia.org/wiki/ITU-R)** によって推奨される **[BT.601標準](https://en.wikipedia.org/wiki/Rec._601)** からの係数を使います。最初のステップは、**輝度を計算する**ことです。ITUに提案されている定数を使い、RGB値を置き換えます。
|
||||
|
||||
```
|
||||
Y = 0.299R + 0.587G + 0.114B
|
||||
```
|
||||
|
||||
輝度をえると次に、**色を分ける** (青の色差と赤の色差)ことができます。
|
||||
|
||||
```
|
||||
Cb = 0.564(B - Y)
|
||||
Cr = 0.713(R - Y)
|
||||
```
|
||||
|
||||
それを**戻す**ことができ、**YCbCrを使って緑**を得ることもできます。
|
||||
|
||||
```
|
||||
R = Y + 1.402Cr
|
||||
B = Y + 1.772Cb
|
||||
G = Y - 0.344Cb - 0.714Cr
|
||||
```
|
||||
|
||||
> <sup>*</sup> グループや標準はデジタルビデオではよくでてきます。彼らは何が標準なのかを定義します。例えば[4Kとは何か?どのフレームレート、解像度、カラーモデルを使うべきか?](https://en.wikipedia.org/wiki/Rec._2020)などです。
|
||||
|
||||
一般的に**ディスプレイ** (モニター、テレビ、スクリーン等) は様々な方法で構成された**RGBモデルだけ**を利用します。下の写真でいくつか拡大したもの示しています。
|
||||
|
||||

|
||||
|
||||
### クロマサブサンプリング
|
||||
|
||||
画像は輝度と色度成分で表現することができるので、人間の視覚システムが色度よりも輝度に敏感であることを利用して情報を選択的に削減することができます。**クロマサブサンプリング**は**色度の解像度を輝度の解像度より小さくする**画像符号化技術です。
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
色度の解像度をどのくらい小さくすべきでしょうか?!解像度と結合 (`最終的な色 = Y + Cb + Cr`)の仕方をどのようにするかを定義したいくつかの方式がすでに存在しています。
|
||||
|
||||
これらの方式はサブサンプリングシステムとして知られ、3つの部分からなる比`a:x:y`として表現されます。これは `a x 2`ブロックの輝度ピクセルに対する色度解像度を定義しています。
|
||||
|
||||
* `a`:横方向のサンプルの基本数。通常は4。
|
||||
* `x`:1ライン目の`a`に現れる色信号サンプルの数。(`a`に対する水平解像度)
|
||||
* `y`:1ライン目と2ライン目での変化数
|
||||
|
||||
> 4:1:0は例外で、`4 x 4`ブロックの輝度に1つの色信号サンプルだけを含んでいます。
|
||||
|
||||
現代のコーデックでよく使われる方式は**4:4:4(サブサンプリング無し)**、**4:2:2、4:1:1、4:2:0、4:1:0、3:1:1**です。
|
||||
|
||||
> **YCbCr 4:2:0結合**
|
||||
>
|
||||
> これがYCbCr 4:2:0を使って結合された画像の断片です。1ピクセルに12ビットしか使わないことに注意してください。
|
||||
>
|
||||
> 
|
||||
|
||||
クロマサブサンプリングの主要な形式で符号化された同じ画像を見て下さい。一行目の画像は最終的なYCbCrで、二行目の画像は色度解像度を示しています。実に小さな劣化で素晴らしい結果です。
|
||||
|
||||

|
||||
|
||||
[解像度が720pで30fpsのビデオを1時間ファイルに保存するためには278GBの領域](#redundancy-removal)が必要になることを先に計算しました。**YCbCr 4:2:0**を使うと、**半分のサイズ(139 GB)**<sup>*</sup>にすることができます。しかしまだ理想には程遠いです。
|
||||
|
||||
> <sup>*</sup> 幅、高さ、ピクセルごとのビット数、フレームレートを掛けることによりこの値を計算しました。先に計算した時は24ビット必要でしたが、今は12ビットしか必要ありません。
|
||||
|
||||
<br/>
|
||||
|
||||
> ### ハンズオン: YCbCrヒストグラムを調べる
|
||||
> [ffmpegでYCbCrヒストグラムを調べる](/encoding_pratical_examples.md#generates-yuv-histogram)ことができます。 このシーンでは青の寄与率がより高くなっています。 [ヒストグラム](https://en.wikipedia.org/wiki/Histogram)でそのことが示されます。
|
||||
>
|
||||
> 
|
||||
|
||||
## フレームの種類
|
||||
|
||||
次に**時間的な冗長性**の削減を試みましょう。しかし、その前にいくつかの基本的用語について押さえておきましょう。30 fpsの動画があり、下記が最初の4フレームであるとします。
|
||||
|
||||
  
|
||||

|
||||
|
||||
**青い背景**のようにフレーム間に**たくさんの繰り返し**を見ることができます。背景はフレーム0からフレーム3まで変化しません。この問題に取り組むために、これらを3種類のフレームに**抽象的に分類**しましょう。
|
||||
|
||||
### Iフレーム (イントラ、キーフレーム)
|
||||
|
||||
Iフレーム(参照、キーフレーム、イントラ)は**自己完結的なフレーム**です。Iフレームは他に依存せずに描画することができ、静止画と似ています。最初のフレームは普通はIフレームですが、他の種類のフレームの間にも規則的にIフレームが挿入されています。
|
||||
|
||||

|
||||
|
||||
### Pフレーム (予測)
|
||||
|
||||
現在の画像は、ほとんど毎回**1つ前のフレームを使って描画する**ことができるという事実をPフレームは利用しています。例えば、2番目のフレームでは、ボールが前に動いたという変化しかありません。**1つ前のフレームを参照し、そのフレームとの差分だけを用いてフレーム1を再構築**できます。
|
||||
|
||||
 <- 
|
||||
|
||||
> #### ハンズオン: Iフレームが1つだけのビデオ
|
||||
> Pフレームはより小さなデータしか使わないので、全体を[Iフレームは1つだけで、他は全てPフレームのビデオ](/encoding_pratical_examples.md#1-i-frame-and-the-rest-p-frames)にエンコードしたらどうでしょう?
|
||||
>
|
||||
> このビデオをエンコードした後、再生してビデオの**前方にシーク**してください。シーク先に移るのに**時間がかかる**ことに気づくでしょう。これは、描画のために**Pフレームが参照フレームを必要とする** (例えばIフレーム)ためです。
|
||||
>
|
||||
> もう1つ手軽にできるテストとして、まず1つのI-Frameだけを使ってビデオをエンコードして、次に[2秒間隔でIフレームを挿入してエンコード](/encoding_pratical_examples.md#1-i-frames-per-second-vs-05-i-frames-per-second)してから、**それぞれのエンコード結果のサイズを比較**してください。
|
||||
|
||||
### Bフレーム (双方向予測)
|
||||
|
||||
過去と未来のフレーム両方を参照したら、さらに高い圧縮率を得ることができるのではないでしょうか?!それがBフレームの基本です。
|
||||
|
||||
 <-  -> 
|
||||
|
||||
> #### ハンズオン: Bフレーム付きのビデオとの比較
|
||||
> 2つの方法でエンコードしてみましょう。1つはBフレーム付きで、もう一方は[Bフレームなし](/encoding_pratical_examples.md#no-b-frames-at-all)でエンコードして、ファイルサイズおよび画質を確認してください。
|
||||
|
||||
### まとめ
|
||||
|
||||
これらの異なる種類のフレームは**より高い圧縮率を得る**ために使われます。次の節でどうやってこれが行われるのか見ていきます。しかし、今のところは**Iフレームは重く、Pフレームは比較的軽いですが、最も軽いのはBフレーム**と考えておいてよいでしょう。
|
||||
|
||||

|
||||
|
||||
## 時間的冗長性 (インター予測)
|
||||
|
||||
**時間的繰り返し**を削減するために何ができるか見ていきましょう。この種の冗長性は**インター予測**という技術で解決することができます。
|
||||
|
||||
|
||||
**できるだけ少ないビットを使って**、連続したフレーム0とフレーム1をエンコードしてみましょう。
|
||||
|
||||

|
||||
|
||||
1つできることとして、引き算があります。単純に**フレーム0からフレーム1を引く**と、**エンコード**する必要がある**差分**を得ることができます。
|
||||
|
||||

|
||||
|
||||
しかし、さらに少ないビットしか使わない**もっとよい方法**があると言ったらどうでしょう!まず、`フレーム0`をきちんと定められた区画の集合であるとします。そして`フレーム0`のそれぞれのブロックを`フレーム1`上にマッチさせようとします。.これは **動き推定**として考えることができます。
|
||||
|
||||
> ### Wikipedia - ブロック動き補償
|
||||
> "**ブロック動き補償**は現在のフレームを重ならないブロックに分けて、動き補償ベクトルは**これらのブロックがどこからのものかを表します** (前回のフレームが重ならないブロックに分けられ、動き補償ベクトルはこれらのブロックがどこへ行くかを表すというのは、よくある誤解です)。 元のブロックは元のフレーム内で通常は重なり合います。ビデオ圧縮アルゴリズムの中には、 すでに送信された異なったいくつかのフレームの断片から現在のフレームを組み立てるものもあります。"
|
||||
|
||||

|
||||
|
||||
ボールが`x=0、y=25`から`x=6、y=26`へ移動したと推定することができます。**x**と**y**の値は**動きベクトル**です。ビットを節約するためのもう1つの**さらなるステップ**は、前回のブロック位置と予測されるブロック位置との**動きベクトルの差分だけをエンコードする**ことです。 最終的な動きベクトルは`x=6 (6-0)、y=1 (26-25)`のようになります。
|
||||
|
||||
> 実際には、この**ボールは分割されてn個の区画にまたがるでしょう**。しかし処理は同じです
|
||||
|
||||
フレーム上の物体は**3D空間で移動します**。ボールは背景の方に動くと小さくもなります。 **完全にマッチするブロックを見つけられない**ことはよくあります。 推定画像と実際の画像を重ねると下記のようになります。
|
||||
|
||||

|
||||
|
||||
しかし、**動き推定**を適用すると、単純なフレーム差分手法を使うよりも**エンコードするデータがより小さくなる**ことが分かります。
|
||||
|
||||

|
||||
|
||||
> ### 可視化された実際の動き補償
|
||||
> この手法は全てのブロックに適用され、高い確率でボールは1つ以上のブロックに配置されます。
|
||||
> 
|
||||
> 引用元: https://web.stanford.edu/class/ee398a/handouts/lectures/EE398a_MotionEstimation_2012.pdf
|
||||
|
||||
[jupyterを使ってこれらの概念を実験](/frame_difference_vs_motion_estimation_plus_residual.ipynb)できます。
|
||||
|
||||
> #### ハンズオン: 動きベクトルを見る
|
||||
> [ffmpegでインター予測 (動きベクトル)付きのビデオを生成する](/encoding_pratical_examples.md#generate-debug-video)ことができます。
|
||||
>
|
||||
> ")
|
||||
>
|
||||
> または、[Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (有料ですが、最初の10フレームに制限された無料お試し版もあります)を使うこともできます。
|
||||
>
|
||||
> 
|
||||
|
||||
## 空間的冗長性 (イントラ予測)
|
||||
|
||||
ビデオの中の**1つ1つのフレーム**を分析すると、**たくさんの相関性のある領域**が存在することが分かります。
|
||||
|
||||

|
||||
|
||||
例を通してみていきましょう。このシーンはほとんど青と白で構成されています。
|
||||
|
||||

|
||||
|
||||
これは `Iフレーム`で、予測のために**前のフレームを使えません**が、圧縮することはできます。赤いブロックを選択してエンコードしてみましょう。**隣接する部分を見る**と、**その周りの色に傾向**があることを**推定**することができます。
|
||||
|
||||

|
||||
|
||||
このフレームでは**色が垂直方向に広がり**続けることを**予測**してみます。**未知のピクセルの色が隣接するピクセルの色を持つ**ことを意味します。
|
||||
|
||||

|
||||
|
||||
**予測が間違うかもしれません**。そのため、この手法(**イントラ予測**)を適用してから、**実際の値を引いて**差分を生成する必要があります。その差分は予測前よりもさらに圧縮しやすいマトリクスになります。
|
||||
|
||||

|
||||
|
||||
> #### ハンズオン: イントラ予測を調べる
|
||||
> [ffmpegでマクロブロックとそれらの予測付きのビデオを生成する](/encoding_pratical_examples.md#generate-debug-video)ことができます。[それぞれのブロックの色の意味](https://trac.ffmpeg.org/wiki/Debug/MacroblocksAndMotionVectors)を理解するためにffmpegのドキュメントを調べてください。
|
||||
>
|
||||
> ")
|
||||
>
|
||||
> または[Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (有料ですが、最初の10フレームに制限された無料お試し版もあります)を使うことができます。
|
||||
>
|
||||
> 
|
||||
|
||||
# ビデオコーデックの仕組み
|
||||
|
||||
## 何か? なぜ? どのように?
|
||||
|
||||
**何か?** デジタルビデオを圧縮、解凍するソフトウェア / ハードウェアの部品。**なぜ?** 制限された帯域とストレージの下でより高い品質のビデオへの要求が、市場と社会で高まっているため。毎秒30フレーム、ピクセルあたり24ビット、解像度が480x240のビデオに[必要な帯域を計算](#basic-terminology)したのを覚えていますか。圧縮なしでは**82.944 Mbps**でした。テレビやインターネットでHD/FullHD/4Kを配信するためには圧縮するしかありません。**どのように?** ここで主な技法について簡単に見ていきます。
|
||||
|
||||
> **コーデック 対 コンテナ**
|
||||
>
|
||||
> 初心者がよく誤解することの1つに、デジタルビデオコーデックと[デジタルビデオコンテナ](https://en.wikipedia.org/wiki/Digital_container_format)を混同するというものがあります。**コンテナ**はビデオ(と音声もありえる)のメタデータとペイロードである**圧縮されたビデオ**を包括するラッパーフォーマットとして考えることができます。
|
||||
>
|
||||
> たいてい、ビデオファイルの拡張子はそのビデオコンテナを定義します。例えば、ファイル`video.mp4`はおそらく **[MPEG-4 Part 14](https://en.wikipedia.org/wiki/MPEG-4_Part_14)** コンテナで、`video.mkv`という名前のファイルはおそらく **[matroska](https://en.wikipedia.org/wiki/Matroska)** です。コーデックとコンテナフォーマットを確実に調べるためには、[ffmpegかmediainfo](/encoding_pratical_examples.md#inspect-stream)が使えます。
|
||||
|
||||
## 歴史
|
||||
|
||||
一般的なコーデックの内部動作に入って行く前に、いくつかの古いビデオコーデックについて少し理解するために過去を振り返ってみましょう。
|
||||
|
||||
ビデオコーデックである[H.261](https://en.wikipedia.org/wiki/H.261)は1990年(厳密には1988年)に生まれました。H.261は**64 kbit/sのデータレート**で動作するように設計されました。クロマサブサンプリングやマクロブロックなどの考えをすでに使っていました。1995年に、**H.263**ビデオコーデック標準が発表され2001年まで拡張され続けました。
|
||||
|
||||
2003年に**H.264/AVC**の初版が完成しました。同じ年に**TrueMotion**と呼ばれる会社が、**ロイヤリティーフリー**で非可逆ビデオ圧縮の **VP3**と呼ばれるビデオコーデックをリリースしました。2008年にこの会社を**Googleが買収**し、同じ年に**VP8**をリリースしました。2012年の12月にGoogleが**VP9**をリリースしました。VP9は(モバイルを含む)**ブラウザ市場のおよそ¾でサポートされています**。
|
||||
|
||||
**[AV1](https://en.wikipedia.org/wiki/AOMedia_Video_1)**は新しい**ロイヤリティーフリー**でオープンソースのビデオコーデックで、[Alliance for Open Media (AOMedia)](http://aomedia.org/)によって設計されました。AOMediaは**複数の会社: Google、Mozilla、Microsoft、Amazon、Netflix、AMD、ARM、NVidia、Intel、Cisco**と他のいくつかの会社から成り立っています。リファレンスコーデックの**初版** 0.1.0が**2016年4月7日に公開されました**。
|
||||
|
||||

|
||||
|
||||
> #### AV1の誕生
|
||||
>
|
||||
> 2015年の初期にGoogleが[VP10](https://en.wikipedia.org/wiki/VP9#Successor:_from_VP10_to_AV1)の開発、Xiph (Mozilla)は[Daala](https://xiph.org/daala/)の開発、Ciscoはオープンソースでロイヤリティーフリーの[Thor](https://tools.ietf.org/html/draft-fuldseth-netvc-thor-03)と呼ばれるビデオコーデックの開発に取り組んでいました。
|
||||
>
|
||||
> MPEG LAは、当初はHEVC (H.265)の年間ロイヤリティーの上限とH.264の8倍高いライセンス料を発表しましたが、すぐにルールを変更しました。:
|
||||
> * **年間ロイヤリティーの上限なし**
|
||||
> * **コンテンツ料金** (収入の0.5%)
|
||||
> * **h264より10倍高い単位あたり料金**
|
||||
>
|
||||
> [alliance for open media](http://aomedia.org/about-us/)はハードウェアメーカー(Intel、AMD、ARM、Nvidia、Cisco)、コンテンツ配信 (Google、Netflix、Amazon)、ブラウザ開発(Google, Mozilla)、その他の会社によって作られました。
|
||||
>
|
||||
> これらの会社にはロイヤリティーフリーのビデオコーデックという共通の目的があり、AV1はより [簡単な特許ライセンス](http://aomedia.org/license/patent/)で誕生しました。**Timothy B. Terriberry**が [AV1の概念、ライセンスモデル、現状](https://www.youtube.com/watch?v=lzPaldsmJbk)についての素晴らしいプレゼンテーションを行いました。この節はこのプレゼンテーションを元に書いています。
|
||||
>
|
||||
> **ブラウザーを使ってAV1コーデックを分析**できることを知って驚くことでしょう。http://aomanalyzer.org/ を見てください。
|
||||
>
|
||||
> 
|
||||
>
|
||||
> 追記: コーデックの歴史についてもっと学びたいなら、背後にある[ビデオ圧縮の特許](https://www.vcodex.com/video-compression-patents/)の基本を学ばなくてはなりません。
|
||||
|
||||
## 一般的コーデック
|
||||
|
||||
**一般的なビデオコーデックの背後にある主な機構**を紹介していきますが、これらの概念のほとんどは VP9、AV1、HEVCのような最新のコーデックでも役に立ち、使われています。物事をかなり単純にして説明することを理解してください。ときどき実際の例(だいたいはH.264)を使って、技法のデモを行います。
|
||||
|
||||
## ステップ1 - 画像分割
|
||||
|
||||
最初のステップは、いくつかの**パーティション、サブパーティション**、もっと細かい単位に**フレームを分割**することです。
|
||||
|
||||

|
||||
|
||||
**しかしなぜ?** たくさんの理由があります。例えば、画像を分割すると小さなパーティションを動きのある小さな部分に使い、より大きなパーティションを静的な背景に使って、予測をより正確に行うことができます。
|
||||
|
||||
通常、コーデックは、スライス(もしくはタイル)、マクロ(もしくは符号ツリーユニット)やたくさんのサブパーティションで **パーティションを構成します**。これらのパーティションの最大サイズは様々で、HEVCでは64x64、AVC16x16ですが、サブパーティションは4x4までです。
|
||||
|
||||
**フレームはいくつかの形式に分けられている**のを学んだことを覚えていますか?!さて、**これらのアイデアをブロックに適用する**こともできます。つまりIスライス、Bスライス、Iマクロブロックなどを持つことができます。
|
||||
|
||||
> ### ハンズオン: パーティションを調べる
|
||||
> [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer) (有料ですが、最初の10フレームに制限された無料お試し版もあります)を使うこともできます。これが分析された[VP9パーティション](/encoding_pratical_examples.md#transcoding)です。
|
||||
>
|
||||
> 
|
||||
|
||||
## ステップ2 - 予測
|
||||
|
||||
パーティションに分割すると、それらについて予測を行うことができます。[インター予測](#temporal-redundancy-inter-prediction)のために、**動きベクトルと差分を送信する**必要があり、また[イントラ予測](#spatial-redundancy-intra-prediction)のために、**予測方向と差分を送信する**必要があります。
|
||||
|
||||
## ステップ3 - 変換
|
||||
|
||||
差分ブロック (`予測パーティション - 実際のパーティション`)を生成した後、それを**変換**することで**画質をある程度**保ったまま、どの**ピクセルを捨てられるか**が分かるようになります。それにはいくつかの変換が存在します。
|
||||
|
||||
[他の変換](https://en.wikipedia.org/wiki/List_of_Fourier-related_transforms#Discrete_transforms)もありますが、離散コサイン変換(DCT)をしっかり見ていきます。[**DCT**](https://en.wikipedia.org/wiki/Discrete_cosine_transform)の主な特徴は:
|
||||
|
||||
* **ピクセル**ブロックを同じサイズの**周波数係数**ブロックに**変換する**。
|
||||
* エネルギーを**圧縮**して、空間的冗長性を削減しやすくする。
|
||||
* **元に戻せる**、またはピクセルに戻せる
|
||||
|
||||
> 2017年2月2日にCintra, R. J.とBayer, F. Mが[14加算のみの画像圧縮用DCT近似変換](https://arxiv.org/abs/1702.00817)という論文を発表しました。
|
||||
|
||||
上記の箇条書きの利点を全て理解しなかったとしても心配いりません。その本当の価値を見い出すためにいくつかの実験を試みます。
|
||||
|
||||
次の**ピクセルのブロック**(8x8)を例にとりましょう:
|
||||
|
||||

|
||||
|
||||
これはブロック画像(8x8)を描画します:
|
||||
|
||||

|
||||
|
||||
このピクセルのブロックに**DCTを適用する**と**係数のブロック** (8x8)を得ます:
|
||||
|
||||

|
||||
|
||||
この係数のブロックを描画すれば、次の画像が得られるでしょう:
|
||||
|
||||

|
||||
|
||||
元の画像とは似ても似つかないことが分かり、**最初の係数**は他の係数とは大きく異なっていることにお気づきかもしれません。この最初の係数はDC係数として知られ、入力配列の**サンプル全体**を表します。**平均に似た**何かです。
|
||||
|
||||
この係数のブロックは高周波数成分を低周波数成分から切り離すという面白い特性を持っています。
|
||||
|
||||

|
||||
|
||||
画像では、**エネルギーのほとんど**は[**低周波**](https://web.archive.org/web/20150129171151/https://www.iem.thm.de/telekom-labor/zinke/mk/mpeg2beg/whatisit.htm)に集中されます。それで画像を周波数成分に変換して**高周波数係数を捨て**れば、画質をそれほど犠牲にせずに画像を表現するのに必要な**データ量を削減**できます。
|
||||
|
||||
> 周波数は信号がどれだけ速く変化するかを意味します。
|
||||
|
||||
では得られた知識を使って、元の画像をDCTを使って周波数(係数のブロック)に変換して、もっとも重要でない係数の部分を捨てる実験をしてみましょう。
|
||||
|
||||
まず、画像を**周波数領域**に変換します。
|
||||
|
||||

|
||||
|
||||
次に、係数の一部(67%)を捨てます。捨てるのはほとんどは右下の部分です。
|
||||
|
||||

|
||||
|
||||
最後に、この一部が捨てられた係数のブロックから画像を再生成し(元に戻せる必要があることを覚えておいてください)、元の画像と比較します。
|
||||
|
||||

|
||||
|
||||
この画像は元の画像と似ていますが、多くの相違点が発生しています。**67.1875%を捨てました**が、 少なくとも元の画像に似ている画像を得ることができました。より賢い方法で係数を捨てて、もっと画質を良くすることもできたのですが、それは次のトピックで扱います。
|
||||
|
||||
> **それぞれの係数は画素全体を使って形成される**
|
||||
>
|
||||
> それぞれの係数は、1つの画素に直接マッピングしているわけではなく、画素全体の重み付き合計であることに留意することは重要です。下記の素晴らしいグラフは、1番目と2番目の係数が、それぞれのインデックスで異なる重みを使って、どのように計算されるかを示しています。
|
||||
>
|
||||
> 
|
||||
>
|
||||
> 原典: https://web.archive.org/web/20150129171151/https://www.iem.thm.de/telekom-labor/zinke/mk/mpeg2beg/whatisit.htm
|
||||
>
|
||||
> DCT基底ごとの[単純な画像の形成を見てDCTを視覚化する](/dct_better_explained.ipynb)こともできます。例えば、下記はそれぞれの係数の重みを使って[1つの文字が形成されていく](https://en.wikipedia.org/wiki/Discrete_cosine_transform#Example_of_IDCT)過程です。
|
||||
>
|
||||
> 
|
||||
|
||||
<br/>
|
||||
|
||||
> ### ハンズオン: 種々の係数を捨てる
|
||||
> [DCT変換](/uniform_quantization_experience.ipynb)を実験しましょう。
|
||||
|
||||
## ステップ4 - 量子化
|
||||
|
||||
前のステップ (変換)で係数をいくつか捨てるときに、量子化のようなものを行いました。このステップでは、捨てる情報(**損失部分**)を選びます。単純な言葉でいうと、**圧縮を成し遂げるために係数を量子化**します。
|
||||
|
||||
どのように係数のブロックを量子化できるでしょうか?1つの単純な方法は、均一量子化でしょう。ブロックを**単一値** (10) **で割り**、小数点を切り捨てます。
|
||||
|
||||

|
||||
|
||||
どのようにこの係数のブロックを**元に戻せる**(再量子化)でしょうか?**同じ値** (10)**を掛ける**ことにより戻すことができます。
|
||||
|
||||

|
||||
|
||||
この**やり方は最適な方法ではありません**。それぞれの係数の重要度を考慮していないからです。 単一値の代わりに**量子化マトリクス**を使うことができます。このマトリクスでDCTの特性を活かすことができます。右下を一番量子化して、左上はあまり量子化しません。[JPEGは似たやり方を使っています](https://www.hdm-stuttgart.de/~maucher/Python/MMCodecs/html/jpegUpToQuant.html)。[ソースコード上でこのマトリクスを見る](https://github.com/google/guetzli/blob/master/guetzli/jpeg_data.h#L40)ことができます。
|
||||
|
||||
> ### ハンズオン: 量子化
|
||||
> [量子化](/dct_experiences.ipynb)を実験しましょう。
|
||||
|
||||
## ステップ5 - エントロピー符号化
|
||||
|
||||
データ(画像 ブロック/スライス/フレーム)を量子化した後、さらに可逆圧縮することができます。データ圧縮のためのたくさんの方法(アルゴリズム)が存在します。それらのいくつかを簡単に体験していきます。より深い理解のためには、この素晴らしい本[Understanding Compression: Data Compression for Modern Developers](https://www.amazon.com/Understanding-Compression-Data-Modern-Developers/dp/1491961538/)を読むとよいでしょう。
|
||||
|
||||
### 可変長符号:
|
||||
|
||||
記号のストリームを持っているとします: **a**、**e**、**r**、**t**とそれらの確率(0から1)がこのテーブルで表されています。
|
||||
|
||||
| | a | e | r | t |
|
||||
|-------------|-----|-----|------|-----|
|
||||
| 確率 | 0.3 | 0.3 | 0.2 | 0.2 |
|
||||
|
||||
もっとも確率が高いものには(より小さな)ユニークなバイナリコードを、もっとも確率が低いものにはより大きなバイナリコードを割り当てることができます。
|
||||
|
||||
| | a | e | r | t |
|
||||
|-------------|-----|-----|------|-----|
|
||||
| probability | 0.3 | 0.3 | 0.2 | 0.2 |
|
||||
| binary code | 0 | 10 | 110 | 1110 |
|
||||
|
||||
ストリーム **eat**を圧縮してみましょう。それぞれの記号に8ビット使うと、圧縮なしで**24ビット**使うことになります。しかし、それぞれの記号をそのコードで置き換えると、スペースを節約できます。
|
||||
|
||||
まず記号**e**を符号化して`10`になります。2つ目の記号**a**を符号化すると、足されて(算数の方法ではなく) `[10][0]`となります。最後に3つ目の記号**t**を符号化すると、最終的な圧縮されたビットストリームは `[10][0][1110]`もしくは`1001110`となり、(もとより3.4倍小さなスペースである)**7ビット**しか使いません。
|
||||
|
||||
それぞれのコードはユニークな接頭符号を持つ必要があることに注意してください [ハフマンがこれらの数字を見つけることを助けてくれます](https://en.wikipedia.org/wiki/Huffman_coding)。いくつかの問題がありますが、この方法は[いくつかのビデオコーデックでまだサポート](https://en.wikipedia.org/wiki/Context-adaptive_variable-length_coding)しています。これは圧縮を必要とする多くのアプリケーションに有用なアルゴリズムです。
|
||||
|
||||
エンコーダーとデコーダーの両方がそのコードの記号テーブルを**知らなくてはいけません**。そのためテーブルも送信する必要があります。
|
||||
|
||||
### 算術符号:
|
||||
|
||||
記号: **a**, **e**, **r**, **s**, **t** のストリームを持っていて、それらの確率がこの表によって表されると仮定しましょう。
|
||||
|
||||
| | a | e | r | s | t |
|
||||
|-------------|-----|-----|------|------|-----|
|
||||
| probability | 0.3 | 0.3 | 0.15 | 0.05 | 0.2 |
|
||||
|
||||
この表を考慮に入れて、出現順にソートされた全ての可能な記号を含む範囲グラフを作ります。
|
||||
|
||||

|
||||
|
||||
さて、ストリーム **eat**を符号化してみましょう。最初の記号**e**を取り上げます。それは**0.3以上0.6未満**に位置しています。この部分範囲を取り上げ、それを再び同じ割合で分割します。
|
||||
|
||||

|
||||
|
||||
ストリーム**eat**の符号化を続けましょう。次に記号**a**を取り上げます。これは**0.3以上0.39未満**に位置しています。そして、最後の記号 **t**を取り上げます。もう一度同じ処理を行うと**0.354以上0.372未満**という最終的な範囲を得ます。
|
||||
|
||||

|
||||
|
||||
最終範囲**0.354以上0.372未満**から1つの数値を取り上げる必要があります。**0.36**を取り上げましょう。しかしこの部分範囲内ならどんな数値を選んでもかまいません。この数値**だけで**、元のストリーム**eat**を復元することができます。これは、ストリームを符号化する為に範囲の範囲に線を引くかのように捉えることができます。
|
||||

|
||||
|
||||
**逆過程** (別名 復号化) は同様に簡単で、数値**0.36**と元の範囲を使って、同じ処理を行い、この数値から符号化されたストリームを明らかにします。
|
||||
|
||||
最初の範囲で、その数値が1つの部分に一致し、それが最初の記号であることに気づきます。それから、その部分範囲を以前行ったようにまた分割します。すると**0.36**が記号**a**に合うことがわかり、同じ処理を繰り返すと、最後の記号である**t**を見つけます(符号前のストリーム*eat*を形成します)。
|
||||
|
||||
符号化と復号化の両方は、記号確率テーブルを**知る必要があります**。それでテーブルを送信する必要があります。
|
||||
|
||||
素晴らしいですよね。人々は本当に賢く、このような解決策を生み出しました。いくつかの[ビデオコーデック](https://en.wikipedia.org/wiki/Context-adaptive_binary_arithmetic_coding)はこの技法を使っています。(もしくは少なくともオプションとして提供しています)。
|
||||
|
||||
この考えは、量子化ビットストリームを可逆圧縮する為のものです。間違いなくこの記事では伝えきれていない詳細、理由、トレードオフ等が山のようにあります。しかし、読者はデベロッパーとして[もっと学ぶべきです](https://www.amazon.com/Understanding-Compression-Data-Modern-Developers/dp/1491961538/)。より新しいコーデックは別の[ANSのようなエントロピー符号化アルゴリズム](https://en.wikipedia.org/wiki/Asymmetric_Numeral_Systems)を使おうとしています。
|
||||
|
||||
> ### ハンズオン: CABAC対CAVLC
|
||||
> [1つはCABAC、もう一方はCAVLCを使って2つのストリームを生成](https://github.com/leandromoreira/introduction_video_technology/blob/master/encoding_pratical_examples.md#cabac-vs-cavlc)し、生成する為にかかる**時間と最終的なサイズを比較**してみましょう。
|
||||
|
||||
## ステップ6 - ビットストリームフォーマット
|
||||
|
||||
これらのステップ全てを行った後、**圧縮されたフレームとこれらのステップまでのコンテキストを一つにまとめる**必要があります。 **エンコーダによってなされた決定**をデコーダへ明示的に知らせる必要があります。ビット深度、色空間、解像度、予測情報(動きベクトル、イントラ予測方向)、プロファイルレベル、フレームレート、フレームタイプ、フレーム数、その他多数です。
|
||||
|
||||
H.264ビットストリームについて表面的に学んでいきます。最初のステップは[最小限のH.264 <sup>*</sup>ビットストリームを生成する](/encoding_pratical_examples.md#generate-a-single-frame-h264-bitstream)ことです。このレポジトリと[ffmpeg](http://ffmpeg.org/)を使って、これができます。
|
||||
|
||||
```
|
||||
./s/ffmpeg -i /files/i/minimal.png -pix_fmt yuv420p /files/v/minimal_yuv420.h264
|
||||
```
|
||||
|
||||
> <sup>*</sup> ffmpegは、デフォルトで**SEI NAL**として符号化された全パラメータを加えます。NALが何であるかは後ほど定義します。
|
||||
|
||||
このコマンドは、**単一フレーム**、64x64、色空間がyuv420、次の画像をフレームとして使っている生のh264ビットストリームを生成します。
|
||||
|
||||
> 
|
||||
|
||||
### H.264ビットストリーム
|
||||
|
||||
AVC (H.264)標準は、情報が **[NAL (Network Abstraction Layer)](https://en.wikipedia.org/wiki/Network_Abstraction_Layer)** と呼ばれる **マクロフレーム** (ネットワーク的には)で送信されることを定義しています。NALの主な目的は、"ネットワークフレンドリー"なビデオ表現を提供することです。この標準は、TV (ストリームベース)、インターネット(パケットベース)やその他で動作しなければなりません。
|
||||
|
||||

|
||||
|
||||
NALユニットの境界を定義する **[同期マーカー](https://en.wikipedia.org/wiki/Frame_synchronization)**があります。それぞれの同期マーカーは、最初は`0x00 0x00 0x00 0x01`で、それ以降は`0x00 0x00 0x01`の値を持ちます。もし生成されたh264ビットストリーム上で**16進ダンプ**を行えば、ファイルの最初の方に、少なくとも3つのNALを見つけることができます。
|
||||
|
||||

|
||||
|
||||
先に述べたとおり、デコーダは画像データだけではなく、動画、フレーム、色、使用されたパラメータ、その他の詳細を知る必要があります。それぞれのNALの**最初のバイト**は、そのカテゴリと**タイプ**を定義します。.
|
||||
|
||||
| NAL タイプID | 説明 |
|
||||
|--- |---|
|
||||
| 0 | 未定義 |
|
||||
| 1 | 非IDRピクチャの符号化スライス |
|
||||
| 2 | 符号化スライスデータパーティション A |
|
||||
| 3 | 符号化スライスデータパーティション B |
|
||||
| 4 | 符号化スライスデータパーティション C |
|
||||
| 5 | IDRピクチャの**IDR**符号化スライス |
|
||||
| 6 | **SEI** 付加拡張情報 |
|
||||
| 7 | **SPS** シーケンスパラメータセット |
|
||||
| 8 | **PPS** ピクチャパラメータセット |
|
||||
| 9 | アクセスユニットデリミター |
|
||||
| 10 | シーケンスの最後 |
|
||||
| 11 | ストリームの最後 |
|
||||
| ... | ... |
|
||||
|
||||
通常、ビットストリームの最初のNALは**SPS**です。このNALの種類は、**プロファイル**、**レベル**、**解像度**やその他の汎用エンコーディング変数を知らせる役割を持ちます。
|
||||
|
||||
最初の同期マーカーを飛ばすと、**最初のバイト**を復号化して**NALのタイプ**が何かを知ることができます。
|
||||
|
||||
例えば、同期マーカーの最初のバイトは`01100111`です。最初のビット (`0`)は**forbidden_zero_bit**フィールドで、次の2ビット(`11`)は**nal_ref_idc**フィールドで、このNALが参照フィールドかどうかを示します。残りの5ビット (`00111`)は**nal_unit_type**フィールドで、この例では**SPS** (7) NALユニットです。
|
||||
|
||||
SPS NALの2バイト目(`2進数=01100100、16進数=0x64、10進数=100`)は**profile_idc**フィールドで、エンコーダが使ったプロファイルを示します。この例では、 **[制約付きハイプロファイル](https://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Profiles)** を使っています。これはB (双方向予測)スライスをサポートしないハイプロファイルです。
|
||||
|
||||

|
||||
|
||||
SPS NALについてH.264ビットストリーム仕様を読むと、**パラメータ名**、**カテゴリ**、**説明**の表に多くの値を見つけるでしょう。例えば、`pic_width_in_mbs_minus_1`と`pic_height_in_map_units_minus_1`フィールドについて見てみましょう。
|
||||
|
||||
| パラメータ名 | カテゴリ | 説明 |
|
||||
|--- |---|---|
|
||||
| pic_width_in_mbs_minus_1 | 0 | ue(v) |
|
||||
| pic_height_in_map_units_minus_1 | 0 | ue(v) |
|
||||
|
||||
> **ue(v)**: 符号なし整数 [Exp-Golomb-coded](https://pythonhosted.org/bitstring/exp-golomb.html)
|
||||
|
||||
これらのフィールドの値に対してある計算をすると、**解像度**を得ることができます。`1920 x 1080`を`pic_width_in_mbs_minus_1`が`119 ( (119 + 1) * macroblock_size = 120 * 16 = 1920) `として表現することができます。空間をさらに節約するために、`1920`を符号化する代わりに、`119`を使っています。
|
||||
|
||||
生成されたビデオをバイナリビュー (例えば: `xxd -b -c 11 v/minimal_yuv420.h264`)で検査し続けると、最後のNALまで飛ばすことができます。それはフレーム自体です。
|
||||
|
||||

|
||||
|
||||
最初の6バイトの値を見ましょう: `01100101 10001000 10000100 00000000 00100001 11111111`。すでに知ってる通り、最初のバイトでNALが何かを知ることができます。この例では、(`00101`)で **IDRスライス (5)** です。さらに検査してみます:
|
||||
|
||||

|
||||
|
||||
仕様の情報を使い、スライスのタイプ (**slice_type**)、フレーム番号(**frame_num**)や他の重要なフィールドを復号することができます。
|
||||
|
||||
いくつかのフィールドの値を得るために(`ue(v)、me(v)、se(v)、te(v)`)、それを[Exponential-Golomb](https://pythonhosted.org/bitstring/exp-golomb.html)と呼ばれる特別なデコーダーを使って、デコードする必要があります。この方法は、デフォルト値が多いケースではたいてい、**変数値を符号化するのにとても効率的**です。
|
||||
|
||||
> このビデオの**slice_type**と**frame_num**の値は7 (Iスライス)と0 (最初のフレーム)です。
|
||||
|
||||
**ビットストリームをプロトコルとして**見ることができます。このビットストリームについてもっと学びたい、もしくは学ぶ必要があるなら、[ITU H.264 spec.]( http://www.itu.int/rec/T-REC-H.264-201610-I)を参照してください。下記はマクロ図表で、ピクチャデータ(圧縮YUV)がどこに位置するかを示しています。
|
||||
|
||||

|
||||
|
||||
[VP9ビットストリーム](https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf)や[H.265 (HEVC)](http://handle.itu.int/11.1002/1000/11885-en?locatt=format:pdf)や、さらには**新しいベストフレドである** [**AV1** ビットストリーム](https://medium.com/@mbebenita/av1-bitstream-analyzer-d25f1c27072b#.d5a89oxz8)のビットストリームを探索することができます。[それらはみんな似てますか?いいえ](http://www.gpac-licensing.com/2016/07/12/vp9-av1-bitstream-format/)、しかし1つを学ぶと、他は簡単に理解できます。
|
||||
|
||||
> ### ハンズオン: H.264ビットストリームを調べる
|
||||
> [単一フレームのビデオを生成](https://github.com/leandromoreira/introduction_video_technology/blob/master/encoding_pratical_examples.md#generate-a-single-frame-video)し、[mediainfo](https://en.wikipedia.org/wiki/MediaInfo)を使ってH.264ビットストリームを検査してみましょう。実際、[h264 (AVC)ビットストリームをパースするソースコード](https://github.com/MediaArea/MediaInfoLib/blob/master/Source/MediaInfo/Video/File_Avc.cpp)を見ることもできます。
|
||||
>
|
||||
> 
|
||||
>
|
||||
> [Intel Video Pro Analyzer](https://software.intel.com/en-us/intel-video-pro-analyzer)を使うこともできます。有料ですが、最初の10フレームに制限された無料お試し版もあり、学習目的としては問題ありません。
|
||||
>
|
||||
> 
|
||||
|
||||
## おさらい
|
||||
|
||||
多くの**現代のコーデックが、これまで学んできた同じモデルを使っている**ことに気づくでしょう。実際のビデオコーデックのブロック図をみてみましょう。これは学んできた全てのステップを含んでいます。少なくともコーデック関連の発明や文献についてより理解することができるようになったことになります。
|
||||
|
||||

|
||||
|
||||
まず[720p解像度で30fpsで1時間のビデオファイルを保存するのに139GBのストレージ](#chroma-subsampling)が必要になることを計算しました。ここで学んだ技法つまり**インター予測、イントラ予測、変形、量子化、エントロピー符号化、その他**を駆使して、**ピクセルあたり0.031ビット**で表現できると仮定すると、**139GBに対したった367.82MBだけ**で同じ知覚画質のビデオを保存できます。
|
||||
|
||||
> 今回使用したビデオを元に**ピクセルあたり0.031ビット**が必要になることを導きました。
|
||||
|
||||
## どのようにH.265はH.264よりも良い圧縮率を実現しているのか?
|
||||
|
||||
今、コーデックの仕組みについてより理解しています。そのため、新しいコーデックがより高い解像度をより少ないビットでどのように配信できるのか簡単に理解できます。
|
||||
|
||||
AVCとHEVCを比較してみましょう。より多くのCPUサイクル(複雑さ)と圧縮率は、ほとんどいつでもトレードオフであることを心に止めておきましょう。
|
||||
|
||||
HEVCはAVCに比べて、より大きく、より多くの**パーティション** (と **サブパーティション**)のオプションを持っています。そしてより多くの**イントラ予測方向**、**改善されたエントロピー符号化**やその他を持っています。これら全ての改良のおかげで、H.265はH.264に比べて50%以上の圧縮をすることができるのです。
|
||||
|
||||

|
||||
|
||||
# オンラインストリーミング
|
||||
## 一般的なアーキテクチャ
|
||||
|
||||

|
||||
|
||||
[TODO]
|
||||
|
||||
## プログレッシブダウンロードとアダプティブストリーミング
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
[TODO]
|
||||
|
||||
## コンテンツ保護
|
||||
|
||||
**単純なトークンシステム**を使ってコンテンツを保護することができます。トークンを持っていないユーザーはビデオをリクエストしようとしても、CDNが禁止します。一方有効なトークンを持つユーザーはそのコンテンツを再生することができます。これはたいていのウェブ認証システムとほとんど同じように動作します。
|
||||
|
||||

|
||||
|
||||
このトークンシステムの一人のユーザーが、あるユーザーにビデオをダウンロードさせて、それを配布させることもできます。**DRM (デジタル著作権管理)** システムを使ってこれを避けることができます。
|
||||
|
||||

|
||||
|
||||
実際の製品システムで、人々はしばしばこれら両方の技術を使って、認可と認証を提供します。
|
||||
|
||||
### DRM
|
||||
#### メインシステム
|
||||
|
||||
* FPS - [**FairPlay Streaming**](https://developer.apple.com/streaming/fps/)
|
||||
* PR - [**PlayReady**](https://www.microsoft.com/playready/)
|
||||
* WV - [**Widevine**](http://www.widevine.com/)
|
||||
|
||||
|
||||
#### 何?
|
||||
|
||||
DRMはデジタル著作権管理を意味します。それは、例えばデジタルビデオやオーディオなどの**デジタルメディアに著作権保護を提供する**方法です。それは多くの場所で使われていますが、[広くは受け入れられていません](https://en.wikipedia.org/wiki/Digital_rights_management#DRM-free_works)。
|
||||
|
||||
#### なぜ?
|
||||
|
||||
コンテンツ製作者(たいていはスタジオ)は、デジタルメディアの不正な再配布を防ぐために、 知的財産が複製されることから守りたいためです。
|
||||
|
||||
#### どのように?
|
||||
|
||||
DRMの抽象的で一般的な形式を、とても単純な方法で説明していきます。
|
||||
|
||||
**コンテンツC1** (例えば hlsやdashビデオストリーミング)と**プレイヤーP1** (例えば shaka-clappr、exo-player、ios)が**デバイスD1** (例えば スマートフォン、テレビ、タブレット、デスクトップ/ノートブック)上にあり、**DRMシステムDRM1** (widevine、playready、FairPlayなど)を使っているとしましょう。
|
||||
|
||||
コンテンツC1は、システムDRM1からの**対称鍵K1**で暗号化され、**暗号化コンテンツC'1**を生成します。
|
||||
|
||||

|
||||
|
||||
デバイスD1のプレイヤーP1は2つの(非対称)鍵、**秘密鍵PRK1** (この鍵は保護され<sup>1</sup>**D1**にしか知られていない)と**公開鍵PUK1**を持っています。
|
||||
|
||||
> **<sup>1</sup>保護される**: この保護は、**ハードウェアを介して**なされます。例えば、この鍵は、特別な(読み取り専用)チップの中に保存されます。これは、復号を提供する[ブラックボックス](https://en.wikipedia.org/wiki/Black_box)のように働きます。もしくは(あまり安全でない)**ソフトウェアにより**なされます。DRM システムは、与えられたデバイスがどのタイプの保護を持っているかを知る方法を提供します。
|
||||
|
||||
**プレイヤーP1がコンテンツC'1を再生したい**とき、**DRMシステムDRM1**を使う必要があり、まず公開鍵**PUK1**を与えます。DRMシステムDRM1は クライアントの公開鍵**PUK1**で**暗号化された鍵K1**を返します。理論上、このレスポンスは**D1だけが復号可能**です。
|
||||
|
||||
`K1P1D1 = enc(K1, PUK1)`
|
||||
|
||||
**P1**は、DRMローカルシステム (それは特別なハードウェアかソフトウェアである[SOC](https://en.wikipedia.org/wiki/System_on_a_chip)もなりえる)を使います。このシステムは、秘密鍵PRK1を使って、コンテンツを**復号することができます**。**K1P1D1からの対称鍵K1**を復号化して、**C'1を再生**することができます。鍵がRAM上で外にさらされないのがベストです。
|
||||
|
||||
```
|
||||
K1 = dec(K1P1D1, PRK1)
|
||||
|
||||
P1.play(dec(C'1, K1))
|
||||
```
|
||||
|
||||

|
||||
|
||||
# jupyterの使い方
|
||||
|
||||
**dockerがインストール**されていることを確認して、`./s/start_jupyter.sh`を実行し、ターミナル上の指示に従ってください。
|
||||
|
||||
# カンファレンス
|
||||
|
||||
* [DEMUXED](https://demuxed.com/) - [最後の2つのイベントプレゼンテーションをチェック](https://www.youtube.com/channel/UCIc_DkRxo9UgUSTvWVNCmpA)することができます。
|
||||
|
||||
# 参考文献
|
||||
|
||||
ここに最高のコンテンツがあります。このテキストで見られる全ては、ここから抽出されたか、元になっているか、何か影響を受けています。この驚くべきリンク、本、動画などで、知識をより深くすることができます。
|
||||
|
||||
オンラインコースとチュートリアル:
|
||||
|
||||
* https://www.coursera.org/learn/digital/
|
||||
* https://people.xiph.org/~tterribe/pubs/lca2012/auckland/intro_to_video1.pdf
|
||||
* https://xiph.org/video/vid1.shtml
|
||||
* https://xiph.org/video/vid2.shtml
|
||||
* http://slhck.info/ffmpeg-encoding-course
|
||||
* http://www.cambridgeincolour.com/tutorials/camera-sensors.htm
|
||||
* http://www.slideshare.net/vcodex/a-short-history-of-video-coding
|
||||
* http://www.slideshare.net/vcodex/introduction-to-video-compression-13394338
|
||||
* https://developer.android.com/guide/topics/media/media-formats.html
|
||||
* http://www.slideshare.net/MadhawaKasun/audio-compression-23398426
|
||||
* http://inst.eecs.berkeley.edu/~ee290t/sp04/lectures/02-Motion_Compensation_girod.pdf
|
||||
|
||||
本:
|
||||
|
||||
* https://www.amazon.com/Understanding-Compression-Data-Modern-Developers/dp/1491961538/ref=sr_1_1?s=books&ie=UTF8&qid=1486395327&sr=1-1
|
||||
* https://www.amazon.com/H-264-Advanced-Video-Compression-Standard/dp/0470516925
|
||||
* https://www.amazon.com/Practical-Guide-Video-Audio-Compression/dp/0240806301/ref=sr_1_3?s=books&ie=UTF8&qid=1486396914&sr=1-3&keywords=A+PRACTICAL+GUIDE+TO+VIDEO+AUDIO
|
||||
* https://www.amazon.com/Video-Encoding-Numbers-Eliminate-Guesswork/dp/0998453005/ref=sr_1_1?s=books&ie=UTF8&qid=1486396940&sr=1-1&keywords=jan+ozer
|
||||
|
||||
ビットストリーム仕様:
|
||||
|
||||
* http://www.itu.int/rec/T-REC-H.264-201610-I
|
||||
* http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=12904&lang=en
|
||||
* https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf
|
||||
* http://iphome.hhi.de/wiegand/assets/pdfs/2012_12_IEEE-HEVC-Overview.pdf
|
||||
* http://phenix.int-evry.fr/jct/doc_end_user/current_document.php?id=7243
|
||||
* http://gentlelogic.blogspot.com.br/2011/11/exploring-h264-part-2-h264-bitstream.html
|
||||
* https://forum.doom9.org/showthread.php?t=167081
|
||||
* https://forum.doom9.org/showthread.php?t=168947
|
||||
|
||||
ソフトウェア:
|
||||
|
||||
* https://ffmpeg.org/
|
||||
* https://ffmpeg.org/ffmpeg-all.html
|
||||
* https://ffmpeg.org/ffprobe.html
|
||||
* https://trac.ffmpeg.org/wiki/
|
||||
* https://software.intel.com/en-us/intel-video-pro-analyzer
|
||||
* https://medium.com/@mbebenita/av1-bitstream-analyzer-d25f1c27072b#.d5a89oxz8
|
||||
|
||||
非ITUコーデック:
|
||||
|
||||
* https://aomedia.googlesource.com/
|
||||
* https://github.com/webmproject/libvpx/tree/master/vp9
|
||||
* https://people.xiph.org/~xiphmont/demo/daala/demo1.shtml
|
||||
* https://people.xiph.org/~jm/daala/revisiting/
|
||||
* https://www.youtube.com/watch?v=lzPaldsmJbk
|
||||
* https://fosdem.org/2017/schedule/event/om_av1/
|
||||
|
||||
エンコードの概念:
|
||||
|
||||
* http://x265.org/hevc-h265/
|
||||
* http://slhck.info/video/2017/03/01/rate-control.html
|
||||
* http://slhck.info/video/2017/02/24/vbr-settings.html
|
||||
* http://slhck.info/video/2017/02/24/crf-guide.html
|
||||
* https://arxiv.org/pdf/1702.00817v1.pdf
|
||||
* https://trac.ffmpeg.org/wiki/Debug/MacroblocksAndMotionVectors
|
||||
* http://web.ece.ucdavis.edu/cerl/ReliableJPEG/Cung/jpeg.html
|
||||
* http://www.adobe.com/devnet/adobe-media-server/articles/h264_encoding.html
|
||||
* https://prezi.com/8m7thtvl4ywr/mp3-and-aac-explained/
|
||||
* https://blogs.gnome.org/rbultje/2016/12/13/overview-of-the-vp9-video-codec/
|
||||
|
||||
テスト用ビデオシーケンス:
|
||||
|
||||
* http://bbb3d.renderfarming.net/download.html
|
||||
* https://www.its.bldrdoc.gov/vqeg/video-datasets-and-organizations.aspx
|
||||
|
||||
その他:
|
||||
|
||||
* http://stackoverflow.com/a/24890903
|
||||
* http://stackoverflow.com/questions/38094302/how-to-understand-header-of-h264
|
||||
* http://techblog.netflix.com/2016/08/a-large-scale-comparison-of-x264-x265.html
|
||||
* http://vanseodesign.com/web-design/color-luminance/
|
||||
* http://www.biologymad.com/nervoussystem/eyenotes.htm
|
||||
* http://www.compression.ru/video/codec_comparison/h264_2012/mpeg4_avc_h264_video_codecs_comparison.pdf
|
||||
* http://www.csc.villanova.edu/~rschumey/csc4800/dct.html
|
||||
* http://www.explainthatstuff.com/digitalcameras.html
|
||||
* http://www.hkvstar.com
|
||||
* http://www.hometheatersound.com/
|
||||
* http://www.lighterra.com/papers/videoencodingh264/
|
||||
* http://www.red.com/learn/red-101/video-chroma-subsampling
|
||||
* http://www.slideshare.net/ManoharKuse/hevc-intra-coding
|
||||
* http://www.slideshare.net/mwalendo/h264vs-hevc
|
||||
* http://www.slideshare.net/rvarun7777/final-seminar-46117193
|
||||
* http://www.springer.com/cda/content/document/cda_downloaddocument/9783642147029-c1.pdf
|
||||
* http://www.streamingmedia.com/Articles/Editorial/Featured-Articles/A-Progress-Report-The-Alliance-for-Open-Media-and-the-AV1-Codec-110383.aspx
|
||||
* http://www.streamingmediaglobal.com/Articles/ReadArticle.aspx?ArticleID=116505&PageNum=1
|
||||
* http://yumichan.net/video-processing/video-compression/introduction-to-h264-nal-unit/
|
||||
* https://cardinalpeak.com/blog/the-h-264-sequence-parameter-set/
|
||||
* https://cardinalpeak.com/blog/worlds-smallest-h-264-encoder/
|
||||
* https://codesequoia.wordpress.com/category/video/
|
||||
* https://developer.apple.com/library/content/technotes/tn2224/_index.html
|
||||
* https://en.wikibooks.org/wiki/MeGUI/x264_Settings
|
||||
* https://en.wikipedia.org/wiki/Adaptive_bitrate_streaming
|
||||
* https://en.wikipedia.org/wiki/AOMedia_Video_1
|
||||
* https://en.wikipedia.org/wiki/Chroma_subsampling#/media/File:Colorcomp.jpg
|
||||
* https://en.wikipedia.org/wiki/Cone_cell
|
||||
* https://en.wikipedia.org/wiki/File:H.264_block_diagram_with_quality_score.jpg
|
||||
* https://en.wikipedia.org/wiki/Inter_frame
|
||||
* https://en.wikipedia.org/wiki/Intra-frame_coding
|
||||
* https://en.wikipedia.org/wiki/Photoreceptor_cell
|
||||
* https://en.wikipedia.org/wiki/Pixel_aspect_ratio
|
||||
* https://en.wikipedia.org/wiki/Presentation_timestamp
|
||||
* https://en.wikipedia.org/wiki/Rod_cell
|
||||
* https://it.wikipedia.org/wiki/File:Pixel_geometry_01_Pengo.jpg
|
||||
* https://leandromoreira.com.br/2016/10/09/how-to-measure-video-quality-perception/
|
||||
* https://sites.google.com/site/linuxencoding/x264-ffmpeg-mapping
|
||||
* https://softwaredevelopmentperestroika.wordpress.com/2014/02/11/image-processing-with-python-numpy-scipy-image-convolution/
|
||||
* https://tools.ietf.org/html/draft-fuldseth-netvc-thor-03
|
||||
* https://www.encoding.com/android/
|
||||
* https://www.encoding.com/http-live-streaming-hls/
|
||||
* https://web.archive.org/web/20150129171151/https://www.iem.thm.de/telekom-labor/zinke/mk/mpeg2beg/whatisit.htm
|
||||
* https://www.lifewire.com/cmos-image-sensor-493271
|
||||
* https://www.linkedin.com/pulse/brief-history-video-codecs-yoav-nativ
|
||||
* https://www.linkedin.com/pulse/video-streaming-methodology-reema-majumdar
|
||||
* https://www.vcodex.com/h264avc-intra-precition/
|
||||
* https://www.youtube.com/watch?v=9vgtJJ2wwMA
|
||||
* https://www.youtube.com/watch?v=LFXN9PiOGtY
|
||||
* https://www.youtube.com/watch?v=Lto-ajuqW3w&list=PLzH6n4zXuckpKAj1_88VS-8Z6yn9zX_P6
|
||||
* https://www.youtube.com/watch?v=LWxu4rkZBLw
|
||||
* https://web.stanford.edu/class/ee398a/handouts/lectures/EE398a_MotionEstimation_2012.pdf
|
||||
+7
-2
@@ -1,4 +1,6 @@
|
||||
[🇨🇳](/simplified-chinese/README-cn.md "Simplified Chinese")
|
||||
[🇨🇳](/README-cn.md "Simplified Chinese")
|
||||
[🇯🇵](/README-ja.md "Japanese")
|
||||
[🇮🇹](/README-it.md "Italian")
|
||||
|
||||
[](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)
|
||||
|
||||
@@ -169,7 +171,6 @@ Our eyes are [more sensitive to brightness than colors](http://vanseodesign.com/
|
||||
If you are unable to see that the colors of the **squares A and B are identical** on the left side, that's fine, it's our brain playing tricks on us to **pay more attention to light and dark than color**. There is a connector, with the same color, on the right side so we (our brain) can easily spot that in fact, they're the same color.
|
||||
|
||||
> **Simplistic explanation of how our eyes work**
|
||||
>
|
||||
> The [eye is a complex organ](http://www.biologymad.com/nervoussystem/eyenotes.htm), it is composed of many parts but we are mostly interested in the cones and rods cells. The eye [contains about 120 million rod cells and 6 million cone cells](https://en.wikipedia.org/wiki/Photoreceptor_cell).
|
||||
>
|
||||
> To **oversimplify**, let's try to put colors and brightness in the eye's parts function. The **[rod cells](https://en.wikipedia.org/wiki/Rod_cell) are mostly responsible for brightness** while the **[cone cells](https://en.wikipedia.org/wiki/Cone_cell) are responsible for color**, there are three types of cones, each with different pigment, namely: [S-cones (Blue), M-cones (Green) and L-cones (Red)](https://upload.wikimedia.org/wikipedia/commons/1/1e/Cones_SMJ2_E.svg).
|
||||
@@ -177,6 +178,10 @@ If you are unable to see that the colors of the **squares A and B are identical*
|
||||
> Since we have many more rod cells (brightness) than cone cells (color), one can infer that we are more capable of distinguishing dark and light than colors.
|
||||
>
|
||||
> 
|
||||
>
|
||||
> **Contrast sensitivity functions**
|
||||
>
|
||||
> Researchers of experimental psychology and many other fields have developed many theories on human vision. And one of them is called Contrast sensitivity functions. They are related to spatio and temporal of the light and their value presents at given init light, how much change is required before an observer reported there was a change. Notice the plural of the word "function", this is for the reason that we can measure Contrast sensitivity functions with not only black-white but also colors. The result of these experiments shows that in most cases our eyes are more sensitive to brightness than color.
|
||||
|
||||
Once we know that we're more sensitive to **luma** (the brightness in an image) we can try to exploit it.
|
||||
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário