Newsgroup: it.comp.software.divx
Titolo: grafici dei bitrate medi dei DivX

per cercare di capire meglio come funzionano i meccanismi di
"rate control" dei codec tipo DivX/XviD, ho scritto un semplice
programmino che genera grafici dei bitrate medi di filmati
generati da tali codec.
il programma si chiama "bitrate-distr" e si usa cosi':
bitrate-distr xvid-600-2pass.avi xvid-600-2pass.png
con questo comando, il programma analizza il filmato
"xvid-600-2pass.avi" e genera l'immagine "xvid-600-2pass.png"
contenente il grafico dei bitrate medi;
il programma e' contenuto (con codice sorgente nel mio
linguaggio e precompilato per linux) nell'archivio "ssim-index",
scaricabile da qui: 
http://fsinapsi.altervista.org
(tra l'altro il calcolo dell'indice ssim con matrice uniforme e'
adesso 2-3 volte piu' veloce, rispetto a due giorni fa)
un esempio di grafico prodotto puo' essere visto qui:
http://fsinapsi.altervista.org/tmp/xvid-600-2pass.png
qualche giorno fa scrissi una bischerata: mi ero meravigliato
del fatto che, analizzando il log di una codifica in seconda
passata il valore "q medio" era un po' piu' alto di quello
ottenuto in una singola passata.
il mio errore consisteva nel credere che la "qualita' media"
(intesa come il passo medio di quantizzazione usato) doveva
essere piu' alta nel caso della seconda passata (cioe', q piu'
basso), ma in realta' le cose stanno in un altro modo:
nel caso di codifica a singola passata (detta anche CBR,
cioe' "a bitrate costante"), l'obiettivo del codec e' quello di
cercare di mantenersi il piu' possibile vicino al target bitrate,
per tutta la codifica (cioe', per tutta la durata del filmato);
nel caso di codifica a piu' passate, il codec ha due obiettivi:
- raggiungere un bitrate medio finale pari al target specificato;
- minimizzare la varianza dei passi di quantizzazione, cioe'
  mantenere la qualita' il piu' possibile costante
vediamo un tipico esempio di film acquisito dalla tv: "bianca"
di nanni moretti, da "skyautore", riscalato a 576x304 (non va
deinterlacciato: i frame acquisiti sono gia' progressivi...)
una analisi del log di una codifica a singola passata, ci dice
questo:
totale frames = 140037
key frames    = 922
q minimo      = 199
q massimo     = 1399
q medio       = 350.469283
varianza      = 14535.750488
e questo per una seconda passata:
totale frames = 140037
key frames    = 946
q minimo      = 192
q massimo     = 711
q medio       = 344.913358
varianza      = 4466.164469
in questo caso, il q medio e' effettivamente un po' piu' basso,
ma non e' quello che veramente importa; il punto cruciale e'
l'abbassamento della varianza... come si puo' vedere, nel caso
della singola passata, il codec e' arrivato a usare un valore
di q pari a 1399 (presumibilmente, cio' vuol dire che in qualche
punto del film, probabilmente nelle scene piu' movimentate e
piu' complesse, si potranno notare artefatti), mentre nel secondo
e' riuscito a non superare 711, quindi le scene peggiori del
secondo filmato saranno sostanzialmente migliori di quelle del
primo...
come ho detto all'inizio, ho scritto il programma "bitrate-distr"
per visualizzare meglio le idee che ho esposto, ma in realta' ero
anche molto interessato a confrontare le diverse distribuzioni di
bitrate nei due codec opensource XviD e lavc;
qua potete vedere altri risultati, ottenuti con questi due codec:
http://fsinapsi.altervista.org/tmp/lavc-600-1pass.png
http://fsinapsi.altervista.org/tmp/xvid-600-1pass.png
http://fsinapsi.altervista.org/tmp/lavc-600-2pass.png
http://fsinapsi.altervista.org/tmp/xvid-600-2pass.png
http://fsinapsi.altervista.org/tmp/lavc-q-2.png
http://fsinapsi.altervista.org/tmp/xvid-q-2.png
e' interessante notare come, questi ultimi due, che mostrano
le distribuzioni di bitrate in caso di codifica a qualita'
costante (quantizer=2), si assomiglino!
si tratta di codec scritti da due team diversi (e in particolare
l'analisi dei motion vectors tra macroblocchi e' implementata da
codice distinto), eppure arrivano entrambi praticamente agli
stessi risultati...
altra cosa interessante da osservare e' l'andamento dei bitrate
nel caso di singola passata (lavc-600-1pass.png e
xvid-600-1pass.png); anche questi si assomigliano molto e in
effetti si assomigliano tutti: e' normale che abbiano quella
forma, perche' l'obiettivo del codec, come ho detto, e' quello
di cercare di mantenersi il piu' possibile vicino al target
bitrate (che nell'esempio e' 600 kbps).
il programma, quindi, puo' essere usato per capire se un certo
DivX e' stato ottenuto con una singola passata o con piu' di
una: si guarda il suo grafico, se assomiglia a quelli visti
(cioe' il bitrate medio parziale e' quasi costante) allora
probabilmente e' stato ottenuto con una sola passata...

 il programma si chiama "bitrate-distr" e si usa cosi':
Applausi, come sempre! ;)
-- 
Saluti, Kap - ICQ 19857429 - ¥'s Fan #01 - 
www.lordkap.it
 - VCC
Chissà come la gente moriva prima dell'invenzione di tante malattie.
Stanislaw J. Lec

 Applausi, come sempre! ;)
in realta' credo che l'idea  di fare un'analisi della distribuzione
dei bitrate medi parziali sia un'idea molto semplice che sia gia'
stata fatta e rifatta nel corso degli anni...
quello che a me interessa e' trovare metodi per confrontare i
meccanismi di "rate control" dei due codec opensource; quello era
il modo piu' semplice, e ha messo in evidenza le similitudini tra
i due codec (in fondo, quella era una delle differenze piu'
importanti, nelle implementazioni, perche' sotto altri aspetti,
usano/riciclano molte librerie che circolano da anni nell'ambiente
opensource...)
prossimamente presentero' i risultati di vari test sugli algoritmi
di resize...
la mia idea e' di usare la funzione di confronto "ssim-index" per
valutare la bonta' di un algoritmo, ma c'e' un problema: tale
confronto puo' essere fatto tra due immagini aventi la stessa
risoluzione, quindi non e' facile scegliere cosa confrontare...
attualmente, la mia idea e' questa:
- parto da una immagine iniziale (ad esempio, un frame di un DVD
  oppure una foto da una camera digitale);
- applicando ogni algoritmo di resize, creo immagini aventi una
  risoluzione diversa (tutte alla stessa risoluzione);
- ad ogni immagine ottenuta al punto precedente, applico ogni
  algoritmo di resize per riottenere una immagine avente le stesse
  risoluzioni dell'immagine di partenza;
- confronto ogni immagine ottenuta al punto precedente con
  l'immagine di partenza (calcolo del ssim-index)
- alla fine stilo una classifica dell'algoritmo che ha ottenuto
  il maggior punteggio medio
dato che gli algoritmi sono 11, i confronti da effettuare sono
11*11=121
naturalmente ci sono molti parametri variabili che potrebbero
influire sul risultato finale del confronto; tali parametri sono:
1) la scelta dell'immagine di partenza;
2) la scelta della risoluzione intermedia;
3) alcuni algoritmi di resize consentono di specificare parametri
   specifici per quell'algoritmo; io sarei propenso a lasciare quelli
   di default, ma, volendo, si possono variare...
4) la scelta della "matrice dei pesi" per calcolare l'indice ssim

   risoluzioni dell'immagine di partenza;
Una cosa rapida su questo punto, poi con più calma leggo tutto il thread.
Facendo come dici tu applichi due volte un algoritmo di resize introducendo
un errore doppio, inoltre nell'ingrandire l'immagine potrebbero presentarsi
errori che normalmente non sono presenti.
Sinceramente non ricordo dove l'ho letto e forse la memoria fa cilecca, ma
ricordo che non tutti i filtri di resize sono adatti per ingrandire
l'immagine. 
In questo caso per fare le prove occorre prendere un filtro come
riferimento e fare le prove con quello. In genere si usa il lanczos perchè
è quello che mantiene più dettagli quando rimpiciolisce. Quindi dovresti
confrontare il fotogramma originale, trattato con il lanczos, con i
fotogrammi ridimensionati con tutti gli altri filtri.
bye, giubbe
-- 
HomePage e FAQ: 
http://giubbe.altervista.org
Inutile scrivere in privato, non ricevo le email

 ingrandire l'immagine.
confermo quello che dici (da 
www.avisynth.org
 " If you are magnifying your 
video, you will get much better-looking results with BicubicResize than with 
BilinearResize. " e anche altro...)
La procedura di confronto delle immagini puo' anche essere ottenuta con le 
MaskTools (plugin che reputo fantastico, se solo lo sapessi usare ...).
In ogni caso: un porting verso Windows ??? ^__^
grazie
Andres Zanzani
Cesena, Italy
www.64k.it/andres
 <-- Tutto per i DivX e non solo 

 fotogrammi ridimensionati con tutti gli altri filtri.
questo e' esattamente cio' che avevo deciso.
poi pero' ho pensato: perche' non ripetere le stesse prove prendendo come
riferimento un altro algoritmo? e perche' non prenderli tutti? in questo
modo si incrociano tutte le possibilita', che sono ( n x n ) (dove n e'
il numero degli algoritmi): prima tratto l'immagine di partenza con un
algoritmo (diciamo lanczos), da essa riottengo n immagini applicando
ciascun algoritmo, ed effettuo i confronti con l'originale; poi ripeto
la stessa cosa, trattando l'immagine con un altro algoritmo (diciamo
bicubic)... e cosi' via, per tutti gli algoritmi.
cio' che conta e' che, per ciascuna prova, tutti gli algoritmi si
trovano nelle stesse condizioni; il loro scopo e' quello di ridimensionare
un'immagine, e se questa presenta difetti rispetto all'originale, anche
i risultati avranno difetti rispetto all'originale, ma gli algoritmi
meno accurati introdurranno ulteriori difetti, e presumibilmente i loro
risultati avranno un indice ssim inferiore...
alla fine faccio una media dei risultati...
in questo modo, do' le stesse identiche possibilita' a tutti gli algoritmi.
che te ne pare?
ho gia' scritto quasi tutto il programma, ecco qui di seguito la parte piu'
importante:
------------------------------------------------------------
(for alg1 in algs do
  (set pmg (call (car alg1) pm
       (rint (* (width pm) 1.3))
       (rint (* (height pm) 1.45)) ))
  (set res (mkarray 0))
  (for alg2 in algs do
    (set pms (call (car alg2) pmg (width pm) (height pm)))
    (set ssim (pix-ssim-index-uniform pm pms))
    (close pms)
    (addarray res (cons ssim (cdr alg2))) )
  (sort rev res minres)
  (printout nl "ingrandimento con " (cdr alg1) nl nl)
  (for alg2 in res do
    (printout (cdr alg2) ": " (car alg2) nl) )
  (close pmg) )
------------------------------------------------------------
e' un doppio ciclo su "algs" (che e' la lista di tutti gli algoritmi):
alg1 e' l'algoritmo usato per trattare l'immagine iniziale, alg2 e'
l'algoritmo usato per riottenere un'immagine avente le dimensioni
originali; pm e' l'immagine originale.
l'istruzione
  (set pmg (call (car alg1) pm
       (rint (* (width pm) 1.3))
       (rint (* (height pm) 1.45)) ))
crea l'immagine che dovra' essere riscalata da tutti gli algoritmi.
mentre l'istruzione
    (set pms (call (car alg2) pmg (width pm) (height pm)))
crea un'immagine avente le dimensioni dell'immagine originale (pm).
infine, l'istruzione
    (set ssim (pix-ssim-index-uniform pm pms))
calcola l'indice ssim tra pm e pms (usando una matrice di pesi
uniforme).
mi resta da aggiungere qualche riga che serva a calcolare le medie
dei punteggi raggiunti...
come ho scritto nel post precedente, il risultato del test
potrebbe essere influenzato da almeno questi 4 fattori:
1) la scelta dell'immagine di partenza;
2) la scelta della risoluzione intermedia;
3) alcuni algoritmi di resize consentono di specificare parametri
   specifici per quell'algoritmo; io sarei propenso a lasciare quelli
   di default, ma, volendo, si possono variare...
4) la scelta della "matrice dei pesi" per calcolare l'indice ssim
per quanto riguarda il punto 1, se qualcuno desidera segnalarmi
un'immagine particolare (o anche piu' di una), mi faccia sapere...
per quanto riguarda il punto 2, nel programma ho usato questa
risoluzione intermedia:
larghezza = (rint (* (width pm) 1.3))
altezza   = (rint (* (height pm) 1.45))
rint e' una funzione che prende un numero e rende il numero intero
piu' vicino (esempio: rint(498.23)=498, rint(1205.763)=1206)
(width pm) x (height pm) e' la risoluzione dell'immagine iniziale;
quindi, per fare un esempio, se l'immagine iniziale ha risoluzione
1000x1000, la risoluzione intermedia sara' 1300x1450
la mia scelta e' tale per cui l'immagine intermedia e' piu' grande
di quella iniziale, quindi viene valutata la capacita' degli
algoritmi di rimpicciolire...
naturalmente e' possibile ripetere la prova facendo il contrario;
cio' si ottiene usando dei fattori di moltiplicazione inferiori
a 1, ad esempio potrei usare questa risoluzione intermedia:
larghezza = (rint (* (width pm) 0.75))
altezza   = (rint (* (height pm) 0.8))
ci sono osservazioni su questo punto?
per quanto riguarda il punto 3, voglio precisare che usero' la
libreria "swscale" di Michael Niedermayer, che ho estratto dalla
directory "postproc" del codice sorgente di MPlayer/MEncoder;
gli algoritmi forniti da tale libreria vengono chiamati cosi':
nearest-neighbour
fast-bilinear
bilinear
bicubic
lanczos
area
luma-bicubic
gauss
sincR
bicubic-spline
buona parte (ma non tutti) di tali algoritmi sono caratterizzati
da una matrice di coefficienti (che, applicata sull'immagine
da scalare, fornisce i valori dei pixel dell'immagine scalata);
i coefficienti sono funzioni della distanza d tra pixel, quindi
tali algoritmi sono definiti da una specifica funzione di un
argomento;
ad esempio, l'algoritmo lanczos e' definito cosi':
 
---------------------------------------
else if(flags & SWS_LANCZOS)
{
  double p = param[0] != SWS_PARAM_DEFAULT ? param[0] : 3.0; 
  coeff = d ? sin(d*PI)*sin(d*PI/p)/(d*d*PI*PI/p) : 1.0;
  if(d>p) coeff=0;
}
---------------------------------------
questa funzione ha un parametro p; la libreria permette
all'utente di specificare un valore per p, ma se non viene
specificato niente, viene assunto per default p=3
ho controllato il codice sorgente di Avisynth, che e' questo:
---------------------------------------
double Lanczos3Filter::sinc(double value)
{
        if (value != 0.0)
        {
                value *= M_PI;
                return sin(value) / value;
        }
        else
        {
                return 1.0;
        }
}
double Lanczos3Filter::f(double value)
{
        if (value < 0.0)
        {
                value = -value;
        }
        if (value < 3.0)
        {
                return (sinc(value) * sinc(value / 3.0));
        }
        else
        {
                return 0.0;
        }
}
---------------------------------------
anche se scritti in forma diversa, si verifica facilmente che
le due implementazioni calcolano gli stessi risultati;
inoltre, anche la versione Avisynth usa un valore di p=3.
lo stesso discorso vale per "bilinear", che in "swscale" e'
implementato cosi':
---------------------------------------
else if(flags & SWS_BILINEAR)
{
  coeff= 1.0 - d;
  if(coeff<0) coeff=0;
}
---------------------------------------
mentre in Avisynth viene chiamato "TriangleFilter", ed e'
definito allo stesso modo:
---------------------------------------
double TriangleFilter::f(double x)
{  
  x = fabs(x);
  return (x<1.0) ? 1.0-x : 0.0;
}
---------------------------------------
un discorso a parte merita "bicubic" (Mitchell-Netravali),
che e' caratterizzato da due parametri (che vengono chiamati
B e C per ragioni storiche); le implementazioni di "swscale" e
di Avisynth coincidono, ma in questo caso la scelta dei
parametri B e C conferisce caratteristiche che forse meritano
di essere trattate come filtri a se' stanti (in alcuni programmi
si distingue tra "sharp bicubic" da altri nomi che non ricordo)
una buona discussione su pregi e difetti delle varie scelte di B e C
si puo' trovare nell'articolo del 1988, "Reconstruction Filters in
Computer Graphics" di Mitchell e Netravali.
ad ogni modo, credo che nei miei test dovrei considerare piu'
scelte dei parametri... se qualcuno mi fornisse i valori di B e C
piu' usati nei programmi, sarebbe una buona cosa...
per quanto riguarda il punto 4 (matrice dei pesi nel ssim),
nell'articolo degli autori dell'indice SSIM si dice che la scelta
di una matrice uniforme 8x8 ha presentato difetti nelle "mappe
di qualita'" e che tali difetti sono spariti passando a usare
una matrice di pesi con distribuzione gaussiana... io ho
implementato entrambe le matrici, ma con quella uniforme il calcolo
e' 7-8 volte piu' veloce... magari eseguiro' i test in entrambi i
modi.
per ora e' tutto.

 In ogni caso: un porting verso Windows ??? ^__^
di cosa? del programma per testare gli algoritmi di resize?
per quello non c'e' problema, basta compilarlo per windows...
per il programma "bitrate-distr" c'e' qualche problema perche'
usa la libreria libplot (dal pacchetto "GNU plotutils") e non
ho idea se abbiano fatto la dll per windows (io non ce l'ho)...

 In ogni caso: un porting verso Windows ??? ^__^
ho compilato e testato sotto windows sia il programma "ssim-index"
che quello per testare gli algoritmi di resize; sembrano funzionare
correttamente, ma il secondo devo ancora finirlo, quindi per il
momento ho rilasciato solo il primo: 
http://fsinapsi.altervista.org
il file (ssim-index.zip) e' lungo 1,168,512 bytes; lo zip contiene
solo l'eseguibile a riga di comando ssim-index.exe (ho spiegato come
si usa nei post precedenti); se manca qualche dll, occorre scaricarla
(sul sito dovrebbero esserci tutte quelle che servono)

 wrote:
Frank> per cercare di capire meglio come funzionano i meccanismi di
Frank> "rate control" dei codec tipo DivX/XviD, ho scritto un semplice
Frank> programmino che genera grafici dei bitrate medi di filmati
Frank> generati da tali codec.
[confronto XVID LAVC]
Frank> e' interessante notare come, questi ultimi due, che mostrano le
Frank> distribuzioni di bitrate in caso di codifica a qualita'
Frank> costante (quantizer=2), si assomiglino!  si tratta di codec
Applausi anche da parte mia per questo studio approfondito e fatto
magistralmente.  E' particolarmente interessante per me il confronto
xvid - lavc perche' la mia esperienza col DVD recorder / DIVX reader
Amstrad DR300 e' che xvid risulta meglio supportato di lavc(mpeg4).
Tra parentesi, io uso normalmente mencoder, e mentre LAVC e' sempre
supportato, le versioni precompilate che trovo in rete sono
senza xvid, per cui mi tocca ricompilare mencoder/mplayer con
xvidcore.
Vedendo l'equivalenza tra i due, sono sempre piu' incline ad usare
xvid, che mi sembra sostanzialmente equivalente.  Qualcuno conosce
confronti tra LAVC e XVID pubblicati in rete?
Saluti.

 xvid, che mi sembra sostanzialmente equivalente.
non solo... l'idea che mi sono fatto e' che generalmente xvid sia un
po' piu' accurato di lavc; cmq i risultati sono molto simili. per
quanto mi riguarda, il grosso difetto di xvid e' la lentezza, pero'
devo ricordarmi di fare un test sulle rispettive velocita'
visto che usi xvid con mencoder, tieni presente che sulla pagina di
manuale c'e' un errore: tra le opzioni di "-xvidencopts" c'e' questa:
-----------------------
max_bframes=<0-4>
   Maximum  number  of B-frames to put between I/P-frames (default:
   0).
-----------------------
in realta', di default i b-frames non sono disabilitati: se provi a
codificare specificando max_bframes=0 ottieni un risultato diverso
rispetto a non specificare niente... quindi il valore di default
non e' 0 (forse e' 2... bisogna provare e controllare...)

 -----------------------
ho controllato: il valore di default e' 2.
(questo potrebbe essere il motivo per cui ho sempre trovato xvid
troppo lento... disabilitando i b-frames e' un po' piu' veloce)

 Nortek 110 non inizia nemmeno a decodificare, per quanto ricordo.
no, funziona; i b-frames non li uso quasi mai, ma ho appena fatto una
prova (il parametro per lavc si chiama "vmax_b_frames") codificando
un filmato sia con che senza b-frames, e il nortek li riproduce bene
entrambi senza che si riescano a notare differenze.
e' con il qpel che non parte nemmeno.
ciao