mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 05:31:01 +00:00 
			
		
		
		
	
		
			
	
	
		
			975 lines
		
	
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			975 lines
		
	
	
	
		
			33 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /********************************************************************
 | ||
|  |  *                                                                  * | ||
|  |  * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   * | ||
|  |  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     * | ||
|  |  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | ||
|  |  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       * | ||
|  |  *                                                                  * | ||
|  |  * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2011                * | ||
|  |  * by the Xiph.Org Foundation http://www.xiph.org/                  *
 | ||
|  |  *                                                                  * | ||
|  |  ******************************************************************** | ||
|  | 
 | ||
|  |   function: mode selection code | ||
|  |   last mod: $Id$ | ||
|  | 
 | ||
|  |  ********************************************************************/ | ||
|  | #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; | ||
|  |   /*Find a non-empty set of metrics.*/ | ||
|  |   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)); | ||
|  |   /*And iterate over the remaining non-empty sets of metrics.*/ | ||
|  |   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; | ||
|  |     /*
 | ||
|  |     (1,1,1) -> | ||
|  |      (0,0,0)# | ||
|  |      (1,0,0) C(1,1)*C(1,0)*C(1,0)->  d^{1,0,0}*(rwa*B_{0,1,1}-rwb*A_{0,1,1}) | ||
|  |      (0,1,0) C(1,0)*C(1,1)*C(1,0)->  d^{0,1,0}*(rwa*B_{1,0,1}-rwb*A_{1,0,1}) | ||
|  |      (0,0,1) C(1,0)*C(1,0)*C(1,1)->  d^{0,0,1}*(rwa*B_{1,1,0}-rwb*A_{1,1,0}) | ||
|  |      (1,1,0)* | ||
|  |      (1,0,1)* | ||
|  |      (0,1,1)* | ||
|  |      (1,1,1) C(1,1)*C(1,1)*C(1,1)->  d^{1,1,1}*(rwa^3*wb-rwb^3*wa) | ||
|  |     (2,1) -> | ||
|  |      (0,0)# | ||
|  |      (1,0) C(2,1)*C(1,1)->2*d^{1,0}*(rwa*B_{1,1}-rwb*A_{1,1}) | ||
|  |      (0,1) C(2,0)*C(1,1)->  d^{0,1}*(rwa*B_{2,0}-rwb*A_{2,0}) | ||
|  |      (2,0)* | ||
|  |      (1,1)* | ||
|  |      (2,1) C(2,2)*C(1,1)->  d^{2,1}*(rwa^3*wb-rwb^3*wa) | ||
|  |     (2,2) -> | ||
|  |      (0,0)# | ||
|  |      (1,0) C(2,1)*C(2,0)->2*d^{1,0}*(rwa*B_{1,2}-rwb*A_{1,2}) | ||
|  |      (0,1) C(2,0)*C(2,1)->2*d^{0,1}*(rwa*B_{2,1}-rwb*A_{2,1}) | ||
|  |      (2,0) C(2,2)*C(2,0)->  d^{2,0}*(rwa^2*B_{0,2}+rwb^2*A_{0,2}) | ||
|  |      (1,1) C(2,1)*C(2,1)->4*d^{1,1}*(rwa^2*B_{1,1}+rwb^2*A_{1,1}) | ||
|  |      (0,2) C(2,0)*C(2,2)->  d^{0,2}*(rwa^2*B_{2,0}+rwb^2*A_{2,0}) | ||
|  |      (1,2)* | ||
|  |      (2,1)* | ||
|  |      (2,2) C(2,2)*C(2,2)*d^{2,2}*(rwa^4*wb+rwb^4*wa) | ||
|  |     */ | ||
|  |     _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; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | /*Adjust a single corner of a set of metric bins to minimize the squared
 | ||
|  |    prediction error of R and D. | ||
|  |   Each bin is assumed to cover a quad like so: | ||
|  |     (s0,q0)    (s1,q0) | ||
|  |        A----------B | ||
|  |        |          | | ||
|  |        |          | | ||
|  |        |          | | ||
|  |        |          | | ||
|  |        C----------Z | ||
|  |     (s0,q1)    (s1,q1) | ||
|  |   The values A, B, and C are fixed, and Z is the free parameter. | ||
|  |   Then, for example, R_i is predicted via bilinear interpolation as | ||
|  |     x_i=(s_i-s0)/(s1-s0) | ||
|  |     y_i=(q_i-q0)/(q1-q0) | ||
|  |     dRds1_i=A+(B-A)*x_i | ||
|  |     dRds2_i=C+(Z-C)*x_i | ||
|  |     R_i=dRds1_i+(dRds2_i-dRds1_i)*y_i | ||
|  |   To find the Z that minimizes the squared prediction error over i, this can | ||
|  |    be rewritten as | ||
|  |     R_i-(A+(B-A)*x_i+(C-A)*y_i+(A-B-C)*x_i*y_i)=x_i*y_i*Z | ||
|  |   Letting X={...,x_i*y_i,...}^T and | ||
|  |    Y={...,R_i-(A+(B-A)*x_i+(C-A)*y_i+(A-B-C)*x_i*y_i),...}^T, | ||
|  |    the optimal Z is given by Z=(X^T.Y)/(X^T.X). | ||
|  |   Now, we need to compute these dot products without actually storing data for | ||
|  |    each sample. | ||
|  |   Starting with X^T.X, we have | ||
|  |    X^T.X = sum(x_i^2*y_i^2) = sum((s_i-s0)^2*(q_i-q0)^2)/((s1-s0)^2*(q1-q0)^2). | ||
|  |   Expanding the interior of the sum in a monomial basis of s_i and q_i gives | ||
|  |     s0^2*q0^2  *(1) | ||
|  |      -2*s0*q0^2*(s_i) | ||
|  |      -2*s0^2*q0*(q_i) | ||
|  |      +q0^2     *(s_i^2) | ||
|  |      +4*s0*q0  *(s_i*q_i) | ||
|  |      +s0^2     *(q_i^2) | ||
|  |      -2*q0     *(s_i^2*q_i) | ||
|  |      -2*s0     *(s_i*q_i^2) | ||
|  |      +1        *(s_i^2*q_i^2). | ||
|  |   However, computing things directly in this basis leads to gross numerical | ||
|  |    errors, as most of the terms will have similar size and destructive | ||
|  |    cancellation results. | ||
|  |   A much better basis is the central (co-)moment basis: | ||
|  |     {1,s_i-sbar,q_i-qbar,(s_i-sbar)^2,(s_i-sbar)*(q_i-qbar),(q_i-qbar)^2, | ||
|  |      (s_i-sbar)^2*(q_i-qbar),(s_i-sbar)*(q_i-qbar)^2,(s_i-sbar)^2*(q_i-qbar)^2}, | ||
|  |    where sbar and qbar are the average s and q values over the bin, | ||
|  |    respectively. | ||
|  |   In that basis, letting ds=sbar-s0 and dq=qbar-q0, (s_i-s0)^2*(q_i-q0)^2 is | ||
|  |     ds^2*dq^2*(1) | ||
|  |      +dq^2   *((s_i-sbar)^2) | ||
|  |      +4*ds*dq*((s_i-sbar)*(q_i-qbar)) | ||
|  |      +ds^2   *((q_i-qbar)^2) | ||
|  |      +2*dq   *((s_i-sbar)^2*(q_i-qbar)) | ||
|  |      +2*ds   *((s_i-sbar)*(q_i-qbar)^2) | ||
|  |      +1      *((s_i-sbar)^2*(q_i-qbar)^2). | ||
|  |   With these expressions in the central (co-)moment bases, all we need to do | ||
|  |    is compute sums over the (co-)moment terms, which can be done | ||
|  |    incrementally (see oc_mode_metrics_add() and oc_mode_metrics_merge()), | ||
|  |    with no need to store the individual samples. | ||
|  |   Now, for X^T.Y, we have | ||
|  |     X^T.Y = sum((R_i-A-((B-A)/(s1-s0))*(s_i-s0)-((C-A)/(q1-q0))*(q_i-q0) | ||
|  |      -((A-B-C)/((s1-s0)*(q1-q0)))*(s_i-s0)*(q_i-q0))*(s_i-s0)*(q_i-q0))/ | ||
|  |      ((s1-s0)*(q1-q0)), | ||
|  |    or, rewriting the constants to simplify notation, | ||
|  |     X^T.Y = sum((C0+C1*(s_i-s0)+C2*(q_i-q0) | ||
|  |      +C3*(s_i-s0)*(q_i-q0)+R_i)*(s_i-s0)*(q_i-q0))/((s1-s0)*(q1-q0)). | ||
|  |   Again, converting to the central (co-)moment basis, the interior of the | ||
|  |    above sum is | ||
|  |     ds*dq*(rbar+C0+C1*ds+C2*dq+C3*ds*dq)  *(1) | ||
|  |      +(C1*dq+C3*dq^2)                     *((s_i-sbar)^2) | ||
|  |      +(rbar+C0+2*C1*ds+2*C2*dq+4*C3*ds*dq)*((s_i-sbar)*(q_i-qbar)) | ||
|  |      +(C2*ds+C3*ds^2)                     *((q_i-qbar)^2) | ||
|  |      +dq                                  *((s_i-sbar)*(r_i-rbar)) | ||
|  |      +ds                                  *((q_i-qbar)*(r_i-rbar)) | ||
|  |      +(C1+2*C3*dq)                        *((s_i-sbar)^2*(q_i-qbar)) | ||
|  |      +(C2+2*C3*ds)                        *((s_i-sbar)*(q_i-qbar)^2) | ||
|  |      +1                                   *((s_i-sbar)*(q_i-qbar)*(r_i-rbar)) | ||
|  |      +C3                                  *((s_i-sbar)^2*(q_i-qbar)^2). | ||
|  |   You might think it would be easier (if perhaps slightly less robust) to | ||
|  |    accumulate terms directly around s0 and q0. | ||
|  |   However, we update each corner of the bins in turn, so we would have to | ||
|  |    change basis to move the sums from corner to corner anyway.*/ | ||
|  | 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; | ||
|  | } | ||
|  | 
 | ||
|  | /*Compile collected SATD/logq/rate/RMSE metrics into a form that's immediately
 | ||
|  |    useful for mode decision.*/ | ||
|  | 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; | ||
|  |   /*The encoder interpolates rate and RMSE terms bilinearly from an
 | ||
|  |      OC_LOGQ_BINS by OC_COMP_BINS grid of sample points in _table. | ||
|  |     To find the sample values at the grid points that minimize the total | ||
|  |      squared prediction error actually requires solving a relatively sparse | ||
|  |      linear system with a number of variables equal to the number of grid | ||
|  |      points. | ||
|  |     Instead of writing a general sparse linear system solver, we just use | ||
|  |      Gauss-Seidel iteration, i.e., we update one grid point at time until | ||
|  |      they stop changing.*/ | ||
|  |   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; | ||
|  |             /*Collect the statistics for the (up to) four bins grid point
 | ||
|  |                (si,qi) touches.*/ | ||
|  |             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); | ||
|  |             } | ||
|  |             /*On the first pass, initialize with a simple weighted average of
 | ||
|  |                the neighboring bins.*/ | ||
|  |             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{ | ||
|  |               /*Update the grid point and save the weight for later.*/ | ||
|  |               _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; | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   /*After a fixed number of initial iterations, only iterate so long as the
 | ||
|  |      total change is decreasing. | ||
|  |     This ensures we don't oscillate forever, which is a danger, as all of our | ||
|  |      results are rounded fairly coarsely.*/ | ||
|  |   while((dr>0||dd>0)&&(niters++<_niters_min||(dr<prevdr&&dd<prevdd))); | ||
|  |   if(_reweight){ | ||
|  |     /*Now, reduce the values of the optimal solution until we get enough
 | ||
|  |        samples in each bin to overcome the constant OC_ZWEIGHT factor. | ||
|  |       This encourages sampling under-populated bins and prevents a single large | ||
|  |        sample early on from discouraging coding in that bin ever again.*/ | ||
|  |     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); | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | /*Dump the in memory mode metrics to a file.
 | ||
|  |   Note this data format isn't portable between different platforms.*/ | ||
|  | 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); | ||
|  |   /*Load any existing mode metrics if we haven't already.*/ | ||
|  |   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){ | ||
|  |       /*Read in the binary structures as written my oc_mode_metrics_dump().
 | ||
|  |         Note this format isn't portable between different platforms.*/ | ||
|  |       (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; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | /*The following token skipping code used to also be used in the decoder (and
 | ||
|  |    even at one point other places in the encoder). | ||
|  |   However, it was obsoleted by other optimizations, and is now only used here. | ||
|  |   It has been moved here to avoid generating the code when it's not needed.*/ | ||
|  | 
 | ||
|  | /*Determines the number of blocks or coefficients to be skipped for a given
 | ||
|  |    token value. | ||
|  |   _token:      The token value to skip. | ||
|  |   _extra_bits: The extra bits attached to this token. | ||
|  |   Return: A positive value indicates that number of coefficients are to be | ||
|  |            skipped in the current block. | ||
|  |           Otherwise, the negative of the return value indicates that number of | ||
|  |            blocks are to be ended.*/ | ||
|  | typedef ptrdiff_t (*oc_token_skip_func)(int _token,int _extra_bits); | ||
|  | 
 | ||
|  | /*Handles the simple end of block tokens.*/ | ||
|  | 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; | ||
|  | } | ||
|  | 
 | ||
|  | /*The last EOB token has a special case, where an EOB run of size zero ends all
 | ||
|  |    the remaining blocks in the frame.*/ | ||
|  | static ptrdiff_t oc_token_skip_eob6(int _token,int _extra_bits){ | ||
|  |   /*Note: We want to return -PTRDIFF_MAX, but that requires C99, which is not
 | ||
|  |      yet available everywhere; this should be equivalent.*/ | ||
|  |   if(!_extra_bits)return -(~(size_t)0>>1); | ||
|  |   return -_extra_bits; | ||
|  | } | ||
|  | 
 | ||
|  | /*Handles the pure zero run tokens.*/ | ||
|  | static ptrdiff_t oc_token_skip_zrl(int _token,int _extra_bits){ | ||
|  |   return _extra_bits+1; | ||
|  | } | ||
|  | 
 | ||
|  | /*Handles a normal coefficient value token.*/ | ||
|  | static ptrdiff_t oc_token_skip_val(void){ | ||
|  |   return 1; | ||
|  | } | ||
|  | 
 | ||
|  | /*Handles a category 1A zero run/coefficient value combo token.*/ | ||
|  | static ptrdiff_t oc_token_skip_run_cat1a(int _token){ | ||
|  |   return _token-OC_DCT_RUN_CAT1A+2; | ||
|  | } | ||
|  | 
 | ||
|  | /*Handles category 1b, 1c, 2a, and 2b zero run/coefficient value combo tokens.*/ | ||
|  | 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; | ||
|  | } | ||
|  | 
 | ||
|  | /*A jump table for computing the number of coefficients or blocks to skip for
 | ||
|  |    a given token value. | ||
|  |   This reduces all the conditional branches, etc., needed to parse these token | ||
|  |    values down to one indirect jump.*/ | ||
|  | 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 | ||
|  | }; | ||
|  | 
 | ||
|  | /*Determines the number of blocks or coefficients to be skipped for a given
 | ||
|  |    token value. | ||
|  |   _token:      The token value to skip. | ||
|  |   _extra_bits: The extra bits attached to this token. | ||
|  |   Return: A positive value indicates that number of coefficients are to be | ||
|  |            skipped in the current block. | ||
|  |           Otherwise, the negative of the return value indicates that number of | ||
|  |            blocks are to be ended. | ||
|  |           0 will never be returned, so that at least one coefficient in one | ||
|  |            block will always be decoded for every token.*/ | ||
|  | 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); | ||
|  |   /*Figure out which metric bins to use for this frame's quantizers.*/ | ||
|  |   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; | ||
|  |   /*Weight the fragments by the inverse frame size; this prevents HD content
 | ||
|  |      from dominating the statistics.*/ | ||
|  |   fragw=1.0/_enc->state.nfrags; | ||
|  |   for(pli=0;pli<3;pli++){ | ||
|  |     ptrdiff_t ti[64]; | ||
|  |     int       eob_token[64]; | ||
|  |     int       eob_run[64]; | ||
|  |     /*Set up token indices and eob run counts.
 | ||
|  |       We don't bother trying to figure out the real cost of the runs that span | ||
|  |        coefficients; instead we use the costs that were available when R-D | ||
|  |        token optimization was done.*/ | ||
|  |     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; | ||
|  |       } | ||
|  |     } | ||
|  |     /*Scan the list of coded fragments for this plane.*/ | ||
|  |     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){ | ||
|  |           /*We've reached the end of the block.*/ | ||
|  |           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){ | ||
|  |           /*This token caused an EOB run to be flushed.
 | ||
|  |             Therefore it gets the bits associated with it.*/ | ||
|  |           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{ | ||
|  |           /*A regular DCT value token; accumulate the bits for it.*/ | ||
|  |           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; | ||
|  |       /*Accumulate statistics.
 | ||
|  |         The rate (frag_bits) and RMSE (sqrt(frag_ssd)) are not scaled by | ||
|  |          OC_BIT_SCALE and OC_RMSE_SCALE; this lets us change the scale factor | ||
|  |          yet still use old data.*/ | ||
|  |       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); | ||
|  |     } | ||
|  |   } | ||
|  |   /*Update global SA(T)D/logq/rate/RMSE estimation matrix.*/ | ||
|  |   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
 |