Tuning of the PVQ RDO and computation of K
authorJean-Marc Valin <jmvalin@jmvalin.ca>
Wed, 1 Aug 2012 02:15:53 +0000 (19:15 -0700)
committerJean-Marc Valin <jmvalin@jmvalin.ca>
Wed, 1 Aug 2012 02:15:53 +0000 (19:15 -0700)
src/encode.c
src/pvq.c

index 506e7e1..8bf325d 100644 (file)
@@ -173,6 +173,8 @@ void fdct4(od_coeff _x[],const od_coeff _y[]){
 }
 #endif
 
+double mode_bits=0;
+double mode_count=0;
 int daala_encode_img_in(daala_enc_ctx *_enc,od_img *_img,int _duration){
   GenericEncoder model_dc;
   GenericEncoder model_g;
@@ -232,7 +234,7 @@ int daala_encode_img_in(daala_enc_ctx *_enc,od_img *_img,int _duration){
     od_state_dump_img(&_enc->state,&_enc->state.vis_img,"vis");
 #endif
   }
-  scale=32;/*atoi(getenv("QUANT"));*/
+  scale=10;/*atoi(getenv("QUANT"));*/
   generic_model_init(&model_dc);
   generic_model_init(&model_g);
   generic_model_init(&model_k);
@@ -327,6 +329,8 @@ int daala_encode_img_in(daala_enc_ctx *_enc,od_img *_img,int _duration){
           mode=od_intra_pred_search(mode_p0,mode_cdf,mode_dist,128,m_l,m_ul,m_u);
           od_intra_pred4x4_get(pred,&ctmp[y*w+x],w,mode);
           od_ec_encode_cdf_unscaled(&_enc->ec,mode,mode_cdf,OD_INTRA_NMODES);
+          mode_bits -= log((mode_cdf[mode]-(mode==0?0:mode_cdf[mode-1]))/(float)mode_cdf[OD_INTRA_NMODES-1])/log(2);
+          mode_count++;
           modes[(y>>2)*(w>>2)+(x>>2)]=mode;
         }else{
           for(j=0;j<16;j++)pred[j]=0;
@@ -344,7 +348,7 @@ int daala_encode_img_in(daala_enc_ctx *_enc,od_img *_img,int _duration){
           }
         }
         sgn=(cblock[0]-predt[0])<0;
-        cblock[0]=floor(pow(fabs(cblock[0]-predt[0])/(scale/2.),3/4.));
+        cblock[0]=floor(pow(fabs(cblock[0]-predt[0])/(scale),3/4.));
         generic_encode(&_enc->ec,&model_dc,cblock[0],&ex_dc,0);
         if(cblock[0])od_ec_enc_bits(&_enc->ec,sgn,1);
         quant_pvq(&cblock[1],&predt[1],pvq_scale,&pred[1],15,scale,&qg);
@@ -353,7 +357,7 @@ int daala_encode_img_in(daala_enc_ctx *_enc,od_img *_img,int _duration){
         vk=0;
         for(j=0;j<15;j++)vk+=abs(pred[j+1]);
         generic_encode(&_enc->ec,&model_k,vk,&ex_k,0);
-        cblock[0]=pow(cblock[0],4/3.)*(scale/2.);
+        cblock[0]=pow(cblock[0],4/3.)*(scale);
         cblock[0]*=sgn?-1:1;
         cblock[0]+=predt[0];
         pvq_encoder(&_enc->ec,&pred[1],15,vk,&anum,&aden,&au);
@@ -470,6 +474,7 @@ int daala_encode_img_in(daala_enc_ctx *_enc,od_img *_img,int _duration){
      pli,(long long)enc_sqerr,npixels,10*log10(255*255.0*npixels/enc_sqerr));
   }
 
+  fprintf(stderr, "mode bits: %f/%f=%f\n", mode_bits,mode_count,mode_bits/mode_count);
   /*Dump YUV*/
   od_state_dump_yuv(&_enc->state,&_enc->state.rec_img,"out");
   _enc->packet_state=OD_PACKET_READY;
index 4fd0691..e595197 100644 (file)
--- a/src/pvq.c
+++ b/src/pvq.c
@@ -376,13 +376,14 @@ int quant_pvq_theta(ogg_int32_t *_x,const ogg_int32_t *_r,
  * @retval position that should have the most pulses in _y
  */
 int quant_pvq(ogg_int32_t *_x,const ogg_int32_t *_r,
-    ogg_int16_t *_scale,int *y,int N,int Q,int *qg){
+    ogg_int16_t *_scale,int *y,int N,int _Q,int *qg){
   float L2x,L2r;
   float g;               /* L2-norm of x */
   float gr;              /* L2-norm of r */
   float x[MAXN];
   float r[MAXN];
   float scale[MAXN];
+  float Q;
   float scale_1[MAXN];
   int   i;
   int   m;
@@ -391,11 +392,12 @@ int quant_pvq(ogg_int32_t *_x,const ogg_int32_t *_r,
   float proj;
   int   K,ym;
   float cg;              /* Companded gain of x*/
+  float cgq;
   float cgr;             /* Companded gain of r*/
   OD_ASSERT(N>1);
 
   /* Just some calibration -- should eventually go away */
-  Q*=.50;
+  Q=_Q*1.3;
 
   for(i=0;i<N;i++){
     scale[i]=_scale[i];
@@ -419,14 +421,28 @@ int quant_pvq(ogg_int32_t *_x,const ogg_int32_t *_r,
 
   /*printf("%f\n", g);*/
   /* compand gain of x and subtract a constant for "pseudo-RDO" purposes */
-  cg = pow(g/Q,GAIN_EXP_1)-1.;
+  cg = pow(g/Q,GAIN_EXP_1);
   if (cg<0)
     cg=0;
-  cgr = pow(gr/Q,GAIN_EXP_1);
+  /* FIXME: Make that 0.2 adaptive */
+  cgr = pow(gr/Q,GAIN_EXP_1)+.2;
 
   /* Gain quantization. Round to nearest because we've already reduced cg.
      Maybe we should have a dead zone */
+#if 0
   *qg = floor(.5+cg-cgr);
+#else
+  /* Doing some RDO on the gain, start by rounding down */
+  *qg = floor(cg-cgr);
+  cgq = cgr+*qg;
+  if (cgq<1e-15) cgq=1e-15;
+  /* Cost difference between rounding up or down */
+  if ( 2*(cgq-cg)+1 + 0.1*(2. + (N-1)*log2(1+1./(cgq)))  < 0)
+  {
+    (*qg)++;
+    cgq = cgr+*qg;
+  }
+#endif
   cg = cgr+*qg;
   if (cg<0)cg=0;
   /* This is the actual gain the decoder will apply */
@@ -435,19 +451,24 @@ int quant_pvq(ogg_int32_t *_x,const ogg_int32_t *_r,
   /* Compute the number of pulses K based on the quantized gain -- still work
      to do here */
 #if 0
-  K = floor(.5+ 1.3*(M_PI/2)*(cg)/GAIN_EXP );
+  K = floor(.5+ 1.*(M_PI/2)*(cg)/GAIN_EXP );
 #else
   if (cg==0){
     K=0;
   }else{
     int K_large;
-    K = cg*cg;
-    K_large = sqrt(cg*N);
+    K = floor(.5+0.6*cg*cg);
+    K_large = floor(.5+1.5*cg*sqrt(N/2));
     if (K>K_large){
       K=K_large;
     }
   }
 #endif
+  if (K==0)
+  {
+    g=0;
+    cg=0;
+  }
   /*if(N==16)printf("%d ", qg);*/
 
   /*if (g>100000 && g0>100000)