#include <stdio.h>
#include <limits.h>
#include <math.h>
#include <string.h>
#include "collect.h"
#if defined(OC_COLLECT_METRICS)
int OC_HAS_MODE_METRICS;
double OC_MODE_RD_WEIGHT_SATD[OC_LOGQ_BINS][3][2][OC_COMP_BINS];
double OC_MODE_RD_WEIGHT_SAD[OC_LOGQ_BINS][3][2][OC_COMP_BINS];
oc_mode_metrics OC_MODE_METRICS_SATD[OC_LOGQ_BINS-1][3][2][OC_COMP_BINS];
oc_mode_metrics OC_MODE_METRICS_SAD[OC_LOGQ_BINS-1][3][2][OC_COMP_BINS];
const char *OC_MODE_METRICS_FILENAME="modedec.stats";
void oc_mode_metrics_add(oc_mode_metrics *_metrics,
double _w,int _s,int _q,int _r,double _d){
if(_metrics->w>0){
double ds;
double dq;
double dr;
double dd;
double ds2;
double dq2;
double s2;
double sq;
double q2;
double sr;
double qr;
double sd;
double qd;
double s2q;
double sq2;
double w;
double wa;
double rwa;
double rwa2;
double rwb;
double rwb2;
double rw2;
double rw3;
double rw4;
wa=_metrics->w;
ds=_s-_metrics->s/wa;
dq=_q-_metrics->q/wa;
dr=_r-_metrics->r/wa;
dd=_d-_metrics->d/wa;
ds2=ds*ds;
dq2=dq*dq;
s2=_metrics->s2;
sq=_metrics->sq;
q2=_metrics->q2;
sr=_metrics->sr;
qr=_metrics->qr;
sd=_metrics->sd;
qd=_metrics->qd;
s2q=_metrics->s2q;
sq2=_metrics->sq2;
w=wa+_w;
rwa=wa/w;
rwb=_w/w;
rwa2=rwa*rwa;
rwb2=rwb*rwb;
rw2=wa*rwb;
rw3=rw2*(rwa2-rwb2);
rw4=_w*rwa2*rwa2+wa*rwb2*rwb2;
_metrics->s2q2+=-2*(ds*sq2+dq*s2q)*rwb
+(ds2*q2+4*ds*dq*sq+dq2*s2)*rwb2+ds2*dq2*rw4;
_metrics->s2q+=(-2*ds*sq-dq*s2)*rwb+ds2*dq*rw3;
_metrics->sq2+=(-ds*q2-2*dq*sq)*rwb+ds*dq2*rw3;
_metrics->sqr+=(-ds*qr-dq*sr-dr*sq)*rwb+ds*dq*dr*rw3;
_metrics->sqd+=(-ds*qd-dq*sd-dd*sq)*rwb+ds*dq*dd*rw3;
_metrics->s2+=ds2*rw2;
_metrics->sq+=ds*dq*rw2;
_metrics->q2+=dq2*rw2;
_metrics->sr+=ds*dr*rw2;
_metrics->qr+=dq*dr*rw2;
_metrics->r2+=dr*dr*rw2;
_metrics->sd+=ds*dd*rw2;
_metrics->qd+=dq*dd*rw2;
_metrics->d2+=dd*dd*rw2;
}
_metrics->w+=_w;
_metrics->s+=_s*_w;
_metrics->q+=_q*_w;
_metrics->r+=_r*_w;
_metrics->d+=_d*_w;
}
void oc_mode_metrics_merge(oc_mode_metrics *_dst,
const oc_mode_metrics *_src,int _n){
int i;
for(i=0;i<_n&&_src[i].w==0;i++);
if(i>=_n){
memset(_dst,0,sizeof(*_dst));
return;
}
memcpy(_dst,_src+i,sizeof(*_dst));
for(i++;i<_n;i++)if(_src[i].w!=0){
double ds;
double dq;
double dr;
double dd;
double ds2;
double dq2;
double s2a;
double s2b;
double sqa;
double sqb;
double q2a;
double q2b;
double sra;
double srb;
double qra;
double qrb;
double sda;
double sdb;
double qda;
double qdb;
double s2qa;
double s2qb;
double sq2a;
double sq2b;
double w;
double wa;
double wb;
double rwa;
double rwb;
double rwa2;
double rwb2;
double rw2;
double rw3;
double rw4;
wa=_dst->w;
wb=_src[i].w;
ds=_src[i].s/wb-_dst->s/wa;
dq=_src[i].q/wb-_dst->q/wa;
dr=_src[i].r/wb-_dst->r/wa;
dd=_src[i].d/wb-_dst->d/wa;
ds2=ds*ds;
dq2=dq*dq;
s2a=_dst->s2;
sqa=_dst->sq;
q2a=_dst->q2;
sra=_dst->sr;
qra=_dst->qr;
sda=_dst->sd;
qda=_dst->qd;
s2qa=_dst->s2q;
sq2a=_dst->sq2;
s2b=_src[i].s2;
sqb=_src[i].sq;
q2b=_src[i].q2;
srb=_src[i].sr;
qrb=_src[i].qr;
sdb=_src[i].sd;
qdb=_src[i].qd;
s2qb=_src[i].s2q;
sq2b=_src[i].sq2;
w=wa+wb;
if(w==0)rwa=rwb=0;
else{
rwa=wa/w;
rwb=wb/w;
}
rwa2=rwa*rwa;
rwb2=rwb*rwb;
rw2=wa*rwb;
rw3=rw2*(rwa2-rwb2);
rw4=wb*rwa2*rwa2+wa*rwb2*rwb2;
_dst->s2q2+=_src[i].s2q2+2*(ds*(rwa*sq2b-rwb*sq2a)+dq*(rwa*s2qb-rwb*s2qa))
+ds2*(rwa2*q2b+rwb2*q2a)+4*ds*dq*(rwa2*sqb+rwb2*sqa)
+dq2*(rwa2*s2b+rwb2*s2a)+ds2*dq2*rw4;
_dst->s2q+=_src[i].s2q+2*ds*(rwa*sqb-rwb*sqa)
+dq*(rwa*s2b-rwb*s2a)+ds2*dq*rw3;
_dst->sq2+=_src[i].sq2+ds*(rwa*q2b-rwb*q2a)
+2*dq*(rwa*sqb-rwb*sqa)+ds*dq2*rw3;
_dst->sqr+=_src[i].sqr+ds*(rwa*qrb-rwb*qra)+dq*(rwa*srb-rwb*sra)
+dr*(rwa*sqb-rwb*sqa)+ds*dq*dr*rw3;
_dst->sqd+=_src[i].sqd+ds*(rwa*qdb-rwb*qda)+dq*(rwa*sdb-rwb*sda)
+dd*(rwa*sqb-rwb*sqa)+ds*dq*dd*rw3;
_dst->s2+=_src[i].s2+ds2*rw2;
_dst->sq+=_src[i].sq+ds*dq*rw2;
_dst->q2+=_src[i].q2+dq2*rw2;
_dst->sr+=_src[i].sr+ds*dr*rw2;
_dst->qr+=_src[i].qr+dq*dr*rw2;
_dst->r2+=_src[i].r2+dr*dr*rw2;
_dst->sd+=_src[i].sd+ds*dd*rw2;
_dst->qd+=_src[i].qd+dq*dd*rw2;
_dst->d2+=_src[i].d2+dd*dd*rw2;
_dst->w+=_src[i].w;
_dst->s+=_src[i].s;
_dst->q+=_src[i].q;
_dst->r+=_src[i].r;
_dst->d+=_src[i].d;
}
}
double oc_mode_metrics_solve(double *_r,double *_d,
const oc_mode_metrics *_metrics,const int *_s0,const int *_s1,
const int *_q0,const int *_q1,
const double *_ra,const double *_rb,const double *_rc,
const double *_da,const double *_db,const double *_dc,int _n){
double xx;
double rxy;
double dxy;
double wt;
int i;
xx=rxy=dxy=wt=0;
for(i=0;i<_n;i++)if(_metrics[i].w>0){
double s10;
double q10;
double sq10;
double ds;
double dq;
double ds2;
double dq2;
double r;
double d;
double s2;
double sq;
double q2;
double sr;
double qr;
double sd;
double qd;
double s2q;
double sq2;
double sqr;
double sqd;
double s2q2;
double c0;
double c1;
double c2;
double c3;
double w;
w=_metrics[i].w;
wt+=w;
s10=_s1[i]-_s0[i];
q10=_q1[i]-_q0[i];
sq10=s10*q10;
ds=_metrics[i].s/w-_s0[i];
dq=_metrics[i].q/w-_q0[i];
ds2=ds*ds;
dq2=dq*dq;
s2=_metrics[i].s2;
sq=_metrics[i].sq;
q2=_metrics[i].q2;
s2q=_metrics[i].s2q;
sq2=_metrics[i].sq2;
s2q2=_metrics[i].s2q2;
xx+=(dq2*(ds2*w+s2)+4*ds*dq*sq+ds2*q2+2*(dq*s2q+ds*sq2)+s2q2)/(sq10*sq10);
r=_metrics[i].r/w;
sr=_metrics[i].sr;
qr=_metrics[i].qr;
sqr=_metrics[i].sqr;
c0=-_ra[i];
c1=-(_rb[i]-_ra[i])/s10;
c2=-(_rc[i]-_ra[i])/q10;
c3=-(_ra[i]-_rb[i]-_rc[i])/sq10;
rxy+=(ds*dq*(r+c0+c1*ds+c2*dq+c3*ds*dq)*w+(c1*dq+c3*dq2)*s2
+(r+c0+2*(c1*ds+(c2+2*c3*ds)*dq))*sq+(c2*ds+c3*ds2)*q2+dq*sr+ds*qr
+(c1+2*c3*dq)*s2q+(c2+2*c3*ds)*sq2+sqr+c3*s2q2)/sq10;
d=_metrics[i].d/w;
sd=_metrics[i].sd;
qd=_metrics[i].qd;
sqd=_metrics[i].sqd;
c0=-_da[i];
c1=-(_db[i]-_da[i])/s10;
c2=-(_dc[i]-_da[i])/q10;
c3=-(_da[i]-_db[i]-_dc[i])/sq10;
dxy+=(ds*dq*(d+c0+c1*ds+c2*dq+c3*ds*dq)*w+(c1*dq+c3*dq2)*s2
+(d+c0+2*(c1*ds+(c2+2*c3*ds)*dq))*sq+(c2*ds+c3*ds2)*q2+dq*sd+ds*qd
+(c1+2*c3*dq)*s2q+(c2+2*c3*ds)*sq2+sqd+c3*s2q2)/sq10;
}
if(xx>1E-3){
*_r=rxy/xx;
*_d=dxy/xx;
}
else{
*_r=0;
*_d=0;
}
return wt;
}
void oc_mode_metrics_update(oc_mode_metrics (*_metrics)[3][2][OC_COMP_BINS],
int _niters_min,int _reweight,oc_mode_rd (*_table)[3][2][OC_COMP_BINS],
int _shift,double (*_weight)[3][2][OC_COMP_BINS]){
int niters;
int prevdr;
int prevdd;
int dr;
int dd;
int pli;
int qti;
int qi;
int si;
dd=dr=INT_MAX;
niters=0;
do{
prevdr=dr;
prevdd=dd;
dd=dr=0;
for(pli=0;pli<3;pli++){
for(qti=0;qti<2;qti++){
for(qi=0;qi<OC_LOGQ_BINS;qi++){
for(si=0;si<OC_COMP_BINS;si++){
oc_mode_metrics m[4];
int s0[4];
int s1[4];
int q0[4];
int q1[4];
double ra[4];
double rb[4];
double rc[4];
double da[4];
double db[4];
double dc[4];
double r;
double d;
int rate;
int rmse;
int ds;
int n;
n=0;
if(qi>0&&si>0){
q0[n]=OC_MODE_LOGQ[qi-1][pli][qti];
q1[n]=OC_MODE_LOGQ[qi][pli][qti];
s0[n]=si-1<<_shift;
s1[n]=si<<_shift;
ra[n]=ldexp(_table[qi-1][pli][qti][si-1].rate,-OC_BIT_SCALE);
da[n]=ldexp(_table[qi-1][pli][qti][si-1].rmse,-OC_RMSE_SCALE);
rb[n]=ldexp(_table[qi-1][pli][qti][si].rate,-OC_BIT_SCALE);
db[n]=ldexp(_table[qi-1][pli][qti][si].rmse,-OC_RMSE_SCALE);
rc[n]=ldexp(_table[qi][pli][qti][si-1].rate,-OC_BIT_SCALE);
dc[n]=ldexp(_table[qi][pli][qti][si-1].rmse,-OC_RMSE_SCALE);
*(m+n++)=*(_metrics[qi-1][pli][qti]+si-1);
}
if(qi>0){
ds=si+1<OC_COMP_BINS?1:-1;
q0[n]=OC_MODE_LOGQ[qi-1][pli][qti];
q1[n]=OC_MODE_LOGQ[qi][pli][qti];
s0[n]=si+ds<<_shift;
s1[n]=si<<_shift;
ra[n]=ldexp(_table[qi-1][pli][qti][si+ds].rate,-OC_BIT_SCALE);
da[n]=
ldexp(_table[qi-1][pli][qti][si+ds].rmse,-OC_RMSE_SCALE);
rb[n]=ldexp(_table[qi-1][pli][qti][si].rate,-OC_BIT_SCALE);
db[n]=ldexp(_table[qi-1][pli][qti][si].rmse,-OC_RMSE_SCALE);
rc[n]=ldexp(_table[qi][pli][qti][si+ds].rate,-OC_BIT_SCALE);
dc[n]=ldexp(_table[qi][pli][qti][si+ds].rmse,-OC_RMSE_SCALE);
*(m+n++)=*(_metrics[qi-1][pli][qti]+si);
}
if(qi+1<OC_LOGQ_BINS&&si>0){
q0[n]=OC_MODE_LOGQ[qi+1][pli][qti];
q1[n]=OC_MODE_LOGQ[qi][pli][qti];
s0[n]=si-1<<_shift;
s1[n]=si<<_shift;
ra[n]=ldexp(_table[qi+1][pli][qti][si-1].rate,-OC_BIT_SCALE);
da[n]=ldexp(_table[qi+1][pli][qti][si-1].rmse,-OC_RMSE_SCALE);
rb[n]=ldexp(_table[qi+1][pli][qti][si].rate,-OC_BIT_SCALE);
db[n]=ldexp(_table[qi+1][pli][qti][si].rmse,-OC_RMSE_SCALE);
rc[n]=ldexp(_table[qi][pli][qti][si-1].rate,-OC_BIT_SCALE);
dc[n]=ldexp(_table[qi][pli][qti][si-1].rmse,-OC_RMSE_SCALE);
*(m+n++)=*(_metrics[qi][pli][qti]+si-1);
}
if(qi+1<OC_LOGQ_BINS){
ds=si+1<OC_COMP_BINS?1:-1;
q0[n]=OC_MODE_LOGQ[qi+1][pli][qti];
q1[n]=OC_MODE_LOGQ[qi][pli][qti];
s0[n]=si+ds<<_shift;
s1[n]=si<<_shift;
ra[n]=ldexp(_table[qi+1][pli][qti][si+ds].rate,-OC_BIT_SCALE);
da[n]=
ldexp(_table[qi+1][pli][qti][si+ds].rmse,-OC_RMSE_SCALE);
rb[n]=ldexp(_table[qi+1][pli][qti][si].rate,-OC_BIT_SCALE);
db[n]=ldexp(_table[qi+1][pli][qti][si].rmse,-OC_RMSE_SCALE);
rc[n]=ldexp(_table[qi][pli][qti][si+ds].rate,-OC_BIT_SCALE);
dc[n]=ldexp(_table[qi][pli][qti][si+ds].rmse,-OC_RMSE_SCALE);
*(m+n++)=*(_metrics[qi][pli][qti]+si);
}
if(!OC_HAS_MODE_METRICS&&niters==0){
double w;
w=r=d=0;
while(n-->0){
w+=m[n].w;
r+=m[n].r;
d+=m[n].d;
}
r=w>1E-3?r/w:0;
d=w>1E-3?d/w:0;
_weight[qi][pli][qti][si]=w;
}
else{
_weight[qi][pli][qti][si]=
oc_mode_metrics_solve(&r,&d,m,s0,s1,q0,q1,ra,rb,rc,da,db,dc,n);
}
rate=OC_CLAMPI(-32768,(int)(ldexp(r,OC_BIT_SCALE)+0.5),32767);
rmse=OC_CLAMPI(-32768,(int)(ldexp(d,OC_RMSE_SCALE)+0.5),32767);
dr+=abs(rate-_table[qi][pli][qti][si].rate);
dd+=abs(rmse-_table[qi][pli][qti][si].rmse);
_table[qi][pli][qti][si].rate=(ogg_int16_t)rate;
_table[qi][pli][qti][si].rmse=(ogg_int16_t)rmse;
}
}
}
}
}
while((dr>0||dd>0)&&(niters++<_niters_min||(dr<prevdr&&dd<prevdd)));
if(_reweight){
for(pli=0;pli<3;pli++){
for(qti=0;qti<2;qti++){
for(qi=0;qi<OC_LOGQ_BINS;qi++){
for(si=0;si<OC_COMP_BINS;si++){
double wt;
wt=_weight[qi][pli][qti][si];
wt/=OC_ZWEIGHT+wt;
_table[qi][pli][qti][si].rate=(ogg_int16_t)
(_table[qi][pli][qti][si].rate*wt+0.5);
_table[qi][pli][qti][si].rmse=(ogg_int16_t)
(_table[qi][pli][qti][si].rmse*wt+0.5);
}
}
}
}
}
}
void oc_mode_metrics_dump(void){
FILE *fmetrics;
fmetrics=fopen(OC_MODE_METRICS_FILENAME,"wb");
if(fmetrics!=NULL){
(void)fwrite(OC_MODE_LOGQ,sizeof(OC_MODE_LOGQ),1,fmetrics);
(void)fwrite(OC_MODE_METRICS_SATD,sizeof(OC_MODE_METRICS_SATD),1,fmetrics);
(void)fwrite(OC_MODE_METRICS_SAD,sizeof(OC_MODE_METRICS_SAD),1,fmetrics);
fclose(fmetrics);
}
}
void oc_mode_metrics_print_rd(FILE *_fout,const char *_table_name,
#if !defined(OC_COLLECT_METRICS)
const oc_mode_rd (*_mode_rd_table)[3][2][OC_COMP_BINS]){
#else
oc_mode_rd (*_mode_rd_table)[3][2][OC_COMP_BINS]){
#endif
int qii;
fprintf(_fout,
"# if !defined(OC_COLLECT_METRICS)\n"
"static const\n"
"# endif\n"
"oc_mode_rd %s[OC_LOGQ_BINS][3][2][OC_COMP_BINS]={\n",_table_name);
for(qii=0;qii<OC_LOGQ_BINS;qii++){
int pli;
fprintf(_fout," {\n");
for(pli=0;pli<3;pli++){
int qti;
fprintf(_fout," {\n");
for(qti=0;qti<2;qti++){
int bin;
int qi;
static const char *pl_names[3]={"Y'","Cb","Cr"};
static const char *qti_names[2]={"INTRA","INTER"};
qi=(63*qii+(OC_LOGQ_BINS-1>>1))/(OC_LOGQ_BINS-1);
fprintf(_fout," /*%s qi=%i %s*/\n",
pl_names[pli],qi,qti_names[qti]);
fprintf(_fout," {\n");
fprintf(_fout," ");
for(bin=0;bin<OC_COMP_BINS;bin++){
if(bin&&!(bin&0x3))fprintf(_fout,"\n ");
fprintf(_fout,"{%5i,%5i}",
_mode_rd_table[qii][pli][qti][bin].rate,
_mode_rd_table[qii][pli][qti][bin].rmse);
if(bin+1<OC_COMP_BINS)fprintf(_fout,",");
}
fprintf(_fout,"\n }");
if(qti<1)fprintf(_fout,",");
fprintf(_fout,"\n");
}
fprintf(_fout," }");
if(pli<2)fprintf(_fout,",");
fprintf(_fout,"\n");
}
fprintf(_fout," }");
if(qii+1<OC_LOGQ_BINS)fprintf(_fout,",");
fprintf(_fout,"\n");
}
fprintf(_fout,
"};\n"
"\n");
}
void oc_mode_metrics_print(FILE *_fout){
int qii;
fprintf(_fout,
"/*File generated by libtheora with OC_COLLECT_METRICS"
" defined at compile time.*/\n"
"#if !defined(_modedec_H)\n"
"# define _modedec_H (1)\n"
"# include \"encint.h\"\n"
"\n"
"\n"
"\n"
"/*The log of the average quantizer for each of the OC_MODE_RD table rows\n"
" (e.g., for the represented qi's, and each pli and qti), in Q10 format.\n"
" The actual statistics used by the encoder will be interpolated from\n"
" that table based on log_plq for the actual quantization matrix used.*/\n"
"# if !defined(OC_COLLECT_METRICS)\n"
"static const\n"
"# endif\n"
"ogg_int16_t OC_MODE_LOGQ[OC_LOGQ_BINS][3][2]={\n");
for(qii=0;qii<OC_LOGQ_BINS;qii++){
fprintf(_fout," { {0x%04X,0x%04X},{0x%04X,0x%04X},{0x%04X,0x%04X} }%s\n",
OC_MODE_LOGQ[qii][0][0],OC_MODE_LOGQ[qii][0][1],OC_MODE_LOGQ[qii][1][0],
OC_MODE_LOGQ[qii][1][1],OC_MODE_LOGQ[qii][2][0],OC_MODE_LOGQ[qii][2][1],
qii+1<OC_LOGQ_BINS?",":"");
}
fprintf(_fout,
"};\n"
"\n");
oc_mode_metrics_print_rd(_fout,"OC_MODE_RD_SATD",OC_MODE_RD_SATD);
oc_mode_metrics_print_rd(_fout,"OC_MODE_RD_SAD",OC_MODE_RD_SAD);
fprintf(_fout,
"#endif\n");
}
# if !defined(OC_COLLECT_NO_ENC_FUNCS)
void oc_enc_mode_metrics_load(oc_enc_ctx *_enc){
oc_restore_fpu(&_enc->state);
if(!OC_HAS_MODE_METRICS){
FILE *fmetrics;
memset(OC_MODE_METRICS_SATD,0,sizeof(OC_MODE_METRICS_SATD));
memset(OC_MODE_METRICS_SAD,0,sizeof(OC_MODE_METRICS_SAD));
fmetrics=fopen(OC_MODE_METRICS_FILENAME,"rb");
if(fmetrics!=NULL){
(void)fread(OC_MODE_LOGQ,sizeof(OC_MODE_LOGQ),1,fmetrics);
(void)fread(OC_MODE_METRICS_SATD,sizeof(OC_MODE_METRICS_SATD),1,fmetrics);
(void)fread(OC_MODE_METRICS_SAD,sizeof(OC_MODE_METRICS_SAD),1,fmetrics);
fclose(fmetrics);
}
else{
int qii;
int qi;
int pli;
int qti;
for(qii=0;qii<OC_LOGQ_BINS;qii++){
qi=(63*qii+(OC_LOGQ_BINS-1>>1))/(OC_LOGQ_BINS-1);
for(pli=0;pli<3;pli++)for(qti=0;qti<2;qti++){
OC_MODE_LOGQ[qii][pli][qti]=_enc->log_plq[qi][pli][qti];
}
}
}
oc_mode_metrics_update(OC_MODE_METRICS_SATD,100,1,
OC_MODE_RD_SATD,OC_SATD_SHIFT,OC_MODE_RD_WEIGHT_SATD);
oc_mode_metrics_update(OC_MODE_METRICS_SAD,100,1,
OC_MODE_RD_SAD,OC_SAD_SHIFT,OC_MODE_RD_WEIGHT_SAD);
OC_HAS_MODE_METRICS=1;
}
}
typedef ptrdiff_t (*oc_token_skip_func)(int _token,int _extra_bits);
static ptrdiff_t oc_token_skip_eob(int _token,int _extra_bits){
int nblocks_adjust;
nblocks_adjust=OC_UNIBBLE_TABLE32(0,1,2,3,7,15,0,0,_token)+1;
return -_extra_bits-nblocks_adjust;
}
static ptrdiff_t oc_token_skip_eob6(int _token,int _extra_bits){
if(!_extra_bits)return -(~(size_t)0>>1);
return -_extra_bits;
}
static ptrdiff_t oc_token_skip_zrl(int _token,int _extra_bits){
return _extra_bits+1;
}
static ptrdiff_t oc_token_skip_val(void){
return 1;
}
static ptrdiff_t oc_token_skip_run_cat1a(int _token){
return _token-OC_DCT_RUN_CAT1A+2;
}
static ptrdiff_t oc_token_skip_run(int _token,int _extra_bits){
int run_cati;
int ncoeffs_mask;
int ncoeffs_adjust;
run_cati=_token-OC_DCT_RUN_CAT1B;
ncoeffs_mask=OC_BYTE_TABLE32(3,7,0,1,run_cati);
ncoeffs_adjust=OC_BYTE_TABLE32(7,11,2,3,run_cati);
return (_extra_bits&ncoeffs_mask)+ncoeffs_adjust;
}
static const oc_token_skip_func OC_TOKEN_SKIP_TABLE[TH_NDCT_TOKENS]={
oc_token_skip_eob,
oc_token_skip_eob,
oc_token_skip_eob,
oc_token_skip_eob,
oc_token_skip_eob,
oc_token_skip_eob,
oc_token_skip_eob6,
oc_token_skip_zrl,
oc_token_skip_zrl,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_val,
(oc_token_skip_func)oc_token_skip_run_cat1a,
(oc_token_skip_func)oc_token_skip_run_cat1a,
(oc_token_skip_func)oc_token_skip_run_cat1a,
(oc_token_skip_func)oc_token_skip_run_cat1a,
(oc_token_skip_func)oc_token_skip_run_cat1a,
oc_token_skip_run,
oc_token_skip_run,
oc_token_skip_run,
oc_token_skip_run
};
static ptrdiff_t oc_dct_token_skip(int _token,int _extra_bits){
return (*OC_TOKEN_SKIP_TABLE[_token])(_token,_extra_bits);
}
void oc_enc_mode_metrics_collect(oc_enc_ctx *_enc){
static const unsigned char OC_ZZI_HUFF_OFFSET[64]={
0,16,16,16,16,16,32,32,
32,32,32,32,32,32,32,48,
48,48,48,48,48,48,48,48,
48,48,48,48,64,64,64,64,
64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64
};
const oc_fragment *frags;
const unsigned *frag_sad;
const unsigned *frag_satd;
const unsigned *frag_ssd;
const ptrdiff_t *coded_fragis;
ptrdiff_t ncoded_fragis;
ptrdiff_t fragii;
double fragw;
int modelines[3][3][2];
int qti;
int qii;
int qi;
int pli;
int zzi;
int token;
int eb;
oc_restore_fpu(&_enc->state);
for(qii=0;qii<_enc->state.nqis;qii++){
for(pli=0;pli<3;pli++){
for(qti=0;qti<2;qti++){
int log_plq;
int modeline;
log_plq=_enc->log_plq[_enc->state.qis[qii]][pli][qti];
for(modeline=0;modeline<OC_LOGQ_BINS-1&&
OC_MODE_LOGQ[modeline+1][pli][qti]>log_plq;modeline++);
modelines[qii][pli][qti]=modeline;
}
}
}
qti=_enc->state.frame_type;
frags=_enc->state.frags;
frag_sad=_enc->frag_sad;
frag_satd=_enc->frag_satd;
frag_ssd=_enc->frag_ssd;
coded_fragis=_enc->state.coded_fragis;
ncoded_fragis=fragii=0;
fragw=1.0/_enc->state.nfrags;
for(pli=0;pli<3;pli++){
ptrdiff_t ti[64];
int eob_token[64];
int eob_run[64];
for(zzi=0;zzi<64;zzi++){
ti[zzi]=_enc->dct_token_offs[pli][zzi];
if(ti[zzi]>0){
token=_enc->dct_tokens[pli][zzi][0];
eb=_enc->extra_bits[pli][zzi][0];
eob_token[zzi]=token;
eob_run[zzi]=-oc_dct_token_skip(token,eb);
}
else{
eob_token[zzi]=OC_NDCT_EOB_TOKEN_MAX;
eob_run[zzi]=0;
}
}
ncoded_fragis+=_enc->state.ncoded_fragis[pli];
for(;fragii<ncoded_fragis;fragii++){
ptrdiff_t fragi;
int frag_bits;
int huffi;
int skip;
int mb_mode;
unsigned sad;
unsigned satd;
double sqrt_ssd;
int bin;
int qtj;
fragi=coded_fragis[fragii];
frag_bits=0;
for(zzi=0;zzi<64;){
if(eob_run[zzi]>0){
eob_run[zzi]--;
break;
}
huffi=_enc->huff_idxs[qti][zzi>0][pli+1>>1]
+OC_ZZI_HUFF_OFFSET[zzi];
if(eob_token[zzi]<OC_NDCT_EOB_TOKEN_MAX){
frag_bits+=_enc->huff_codes[huffi][eob_token[zzi]].nbits
+OC_DCT_TOKEN_EXTRA_BITS[eob_token[zzi]];
eob_token[zzi]=OC_NDCT_EOB_TOKEN_MAX;
}
token=_enc->dct_tokens[pli][zzi][ti[zzi]];
eb=_enc->extra_bits[pli][zzi][ti[zzi]];
ti[zzi]++;
skip=oc_dct_token_skip(token,eb);
if(skip<0){
eob_token[zzi]=token;
eob_run[zzi]=-skip;
}
else{
frag_bits+=_enc->huff_codes[huffi][token].nbits
+OC_DCT_TOKEN_EXTRA_BITS[token];
zzi+=skip;
}
}
mb_mode=frags[fragi].mb_mode;
qii=frags[fragi].qii;
qi=_enc->state.qis[qii];
sad=frag_sad[fragi]<<(pli+1&2);
satd=frag_satd[fragi]<<(pli+1&2);
sqrt_ssd=sqrt(frag_ssd[fragi]);
qtj=mb_mode!=OC_MODE_INTRA;
bin=OC_MINI(satd>>OC_SATD_SHIFT,OC_COMP_BINS-1);
oc_mode_metrics_add(
OC_MODE_METRICS_SATD[modelines[qii][pli][qtj]][pli][qtj]+bin,
fragw,satd,_enc->log_plq[qi][pli][qtj],frag_bits,sqrt_ssd);
bin=OC_MINI(sad>>OC_SAD_SHIFT,OC_COMP_BINS-1);
oc_mode_metrics_add(
OC_MODE_METRICS_SAD[modelines[qii][pli][qtj]][pli][qtj]+bin,
fragw,sad,_enc->log_plq[qi][pli][qtj],frag_bits,sqrt_ssd);
}
}
oc_mode_metrics_update(OC_MODE_METRICS_SATD,4,1,
OC_MODE_RD_SATD,OC_SATD_SHIFT,OC_MODE_RD_WEIGHT_SATD);
oc_mode_metrics_update(OC_MODE_METRICS_SAD,4,1,
OC_MODE_RD_SAD,OC_SAD_SHIFT,OC_MODE_RD_WEIGHT_SAD);
}
# endif
#endif