[xiph-commits] r15109 - branches/theora-thusnelda/lib/enc

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Thu Jul 10 20:07:44 PDT 2008


Author: xiphmont
Date: 2008-07-10 20:07:43 -0700 (Thu, 10 Jul 2008)
New Revision: 15109

Modified:
   branches/theora-thusnelda/lib/enc/codec_internal.h
   branches/theora-thusnelda/lib/enc/dct_encode.c
   branches/theora-thusnelda/lib/enc/encode.c
   branches/theora-thusnelda/lib/enc/encoder_toplevel.c
   branches/theora-thusnelda/lib/enc/mode.c
Log:
Commit first cut of per-token optimization.  Like SKIP blocks, it does not yet automatically choose its lambda.



Modified: branches/theora-thusnelda/lib/enc/codec_internal.h
===================================================================
--- branches/theora-thusnelda/lib/enc/codec_internal.h	2008-07-10 04:17:49 UTC (rev 15108)
+++ branches/theora-thusnelda/lib/enc/codec_internal.h	2008-07-11 03:07:43 UTC (rev 15109)
@@ -233,7 +233,20 @@
   int              readyflag;
   int              packetflag;
   int              doneflag;
-  
+  int              first_inter_frame;
+
+  int              huffchoice[2][2][2]; /* [key/inter][dc/ac][luma/chroma] */
+
+  ogg_uint32_t     dc_bits[2][DC_HUFF_CHOICES];
+  ogg_uint32_t     ac1_bits[2][AC_HUFF_CHOICES];
+  ogg_uint32_t     acN_bits[2][AC_HUFF_CHOICES];
+
+  ogg_uint32_t     MVBits_0; /* count of bits used by MV coding mode 0 */
+  ogg_uint32_t     MVBits_1; /* count of bits used by MV coding mode 1 */
+
+  oc_mode_scheme_chooser chooser;
+
+
   /*********************************************************************/
   /* Token Buffers */
   int             *fr_partial;
@@ -252,19 +265,10 @@
   ogg_int32_t      dct_token_count[64];
   ogg_int32_t      dct_token_ycount[64];
 
-  ogg_uint32_t     dc_bits[2][DC_HUFF_CHOICES];
-  ogg_uint32_t     ac1_bits[2][AC_HUFF_CHOICES];
-  ogg_uint32_t     acN_bits[2][AC_HUFF_CHOICES];
-
   int              eob_run[64];
   int              eob_pre[64];
   int              eob_ypre[64];
 
-  oc_mode_scheme_chooser chooser;
-
-  ogg_uint32_t     MVBits_0; /* count of bits used by MV coding mode 0 */
-  ogg_uint32_t     MVBits_1; /* count of bits used by MV coding mode 1 */
-
   /********************************************************************/
   /* Fragment SAD->bitrate estimation tracking metrics */
   long             rho_count[65]; 
@@ -284,6 +288,7 @@
   int              keyframe_granule_shift;
   int              skip_lambda;
   int              mv_lambda;
+  int              token_lambda;
   int              BaseQ;
   int              GoldenFrameEnabled;
   int              InterPrediction;
@@ -323,10 +328,20 @@
   int run;
 } token_checkpoint_t;
 
-extern void tokenlog_commit(CP_INSTANCE *cpi, token_checkpoint_t *stack, int n);
-extern void tokenlog_rollback(CP_INSTANCE *cpi, token_checkpoint_t *stack,int n);
+extern void tokenlog_commit(CP_INSTANCE *cpi, 
+			    token_checkpoint_t *stack, 
+			    int n);
+extern void tokenlog_rollback(CP_INSTANCE *cpi, 
+			      token_checkpoint_t *stack,
+			      int n);
 extern void dct_tokenize_init (CP_INSTANCE *cpi);
-extern void dct_tokenize_AC (CP_INSTANCE *cpi, int fi, ogg_int16_t *dct, int chroma, token_checkpoint_t **stack);
+extern void dct_tokenize_AC (CP_INSTANCE *cpi, 
+			     int fi, 
+			     ogg_int16_t *dct, 
+			     ogg_int16_t *dequant, 
+			     ogg_int16_t *origdct, 
+			     int chroma, 
+			     token_checkpoint_t **stack);
 extern void dct_tokenize_finish (CP_INSTANCE *cpi);
 extern void dct_tokenize_mark_ac_chroma (CP_INSTANCE *cpi);
 

Modified: branches/theora-thusnelda/lib/enc/dct_encode.c
===================================================================
--- branches/theora-thusnelda/lib/enc/dct_encode.c	2008-07-10 04:17:49 UTC (rev 15108)
+++ branches/theora-thusnelda/lib/enc/dct_encode.c	2008-07-11 03:07:43 UTC (rev 15109)
@@ -216,13 +216,13 @@
    able to undo a fragment's tokens on a whim */
 
 static int acoffset[64]={
-  16,16,16,16,16,16, 32,32,
-  32,32,32,32,32,32,32, 48,
+  00,00,00,00,00,00,16,16,
+  16,16,16,16,16,16,16,32,
+  32,32,32,32,32,32,32,32,
+  32,32,32,32,48,48,48,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};
+  48,48,48,48,48,48,48,48,
+  48,48,48,48,48,48,48,48};
 
 void tokenlog_rollback(CP_INSTANCE *cpi, token_checkpoint_t *stack,int n){
   int i;
@@ -242,12 +242,12 @@
       cpi->dc_bits[chroma][i] += cpi->HuffCodeLengthArray_VP3x[i][token];
   }else if (coeff == 1){
     /* AC == 1*/
-    int i,offset = acoffset[1];
+    int i,offset = acoffset[1]+AC_HUFF_OFFSET;
     for ( i = 0; i < AC_HUFF_CHOICES; i++)
       cpi->ac1_bits[chroma][i] += cpi->HuffCodeLengthArray_VP3x[offset+i][token];
   }else{
     /* AC > 1*/
-    int i,offset = acoffset[coeff];
+    int i,offset = acoffset[coeff]+AC_HUFF_OFFSET;
     for ( i = 0; i < AC_HUFF_CHOICES; i++)
       cpi->acN_bits[chroma][i] += cpi->HuffCodeLengthArray_VP3x[offset+i][token];
   }
@@ -394,29 +394,131 @@
 #endif
 }
 
+/* only counts bits */
+static int tokencost(CP_INSTANCE *cpi, int huff, int coeff, int token){
+  huff += acoffset[coeff];
+  return cpi->HuffCodeLengthArray_VP3x[huff][token] + cpi->ExtraBitLengths_VP3x[token];
+}
+
+static int tokenize_dctcost(CP_INSTANCE *cpi,int chroma,
+			     int coeff, int coeff2, int val){
+  int huff = cpi->huffchoice[cpi->FrameType!=KEY_FRAME][1][chroma];
+  int eb=0,token=0;
+  int cost = 0;
+  
+  /* if there was an EOB run pending, count the cost of flushing it */
+  if(cpi->eob_run[coeff]){
+    make_eobrun_token(cpi->eob_run[coeff],&token,&eb);
+    cost += tokencost(cpi,huff,coeff,token);
+  }
+
+  /* count cost of token */
+  token = make_dct_token(cpi,coeff,coeff2,val,&eb);
+  cost += tokencost(cpi,huff, coeff, token);
+  
+  /* if token was a zero run, we've not yet coded up to the value */
+  if( (token==DCT_SHORT_ZRL_TOKEN) || (token==DCT_ZRL_TOKEN))
+    return cost + tokenize_dctcost(cpi,chroma,coeff2,coeff2,val);
+  else
+    return cost;
+}
+
+/* The opportunity cost of an in-progress EOB run is the cost to flush
+   the run up to 'n+1' minus the cost of flushing the run up to 'n' */
+static int tokenize_eobcost(CP_INSTANCE *cpi,int chroma, int coeff){
+  int n = cpi->eob_run[coeff];
+  int eb=0,token=0;
+  int cost0=0,cost1;
+  
+  if(n>0){
+    int huff = cpi->huffchoice[cpi->FrameType!=KEY_FRAME][1][!(n&0x8000)];
+
+    make_eobrun_token(n&0x7fff, &token, &eb);
+    cost0 = tokencost(cpi,huff,coeff,token);
+
+    make_eobrun_token((n+1)&0x7fff, &token, &eb);
+    cost1 = tokencost(cpi,huff,coeff,token);
+    
+  }else{
+    int huff = cpi->huffchoice[cpi->FrameType!=KEY_FRAME][1][chroma];
+    cost1 = tokencost(cpi,huff,coeff,DCT_EOB_TOKEN);
+  }    
+
+  return cost1-cost0;
+}
+
 /* No final DC to encode yet (DC prediction hasn't been done) So
    simply assume there will be a nonzero DC value and code.  That's
    not a true assumption but it can be fixed-up as DC is tokenized
    later */
-
-void dct_tokenize_AC(CP_INSTANCE *cpi, int fi, ogg_int16_t *dct, int chroma, token_checkpoint_t **stack){
+void dct_tokenize_AC(CP_INSTANCE *cpi, int fi, 
+		     ogg_int16_t *dct, ogg_int16_t *dequant, ogg_int16_t *origdct, 
+		     int chroma, token_checkpoint_t **stack){
   int coeff = 1; /* skip DC for now */
   while(coeff < BLOCK_SIZE){
-    ogg_int16_t val = dct[coeff];
     int i = coeff;
+    int ret;
+
+    while( !dct[i] && (++i < BLOCK_SIZE) );
     
-    while( !val && (++i < BLOCK_SIZE) )
-      val = dct[i];
-    
     if ( i == BLOCK_SIZE ){
       
-      /* if there are no other tokens in this group yet, set up to be
-	 prepended later.  */
       tokenize_mark_run(cpi,chroma,fi,coeff>1,coeff,stack);
       coeff = BLOCK_SIZE;
     }else{
-      
-      coeff = tokenize_dctval(cpi, chroma, fi, coeff, i, val, stack) + i;
+
+      /* determine costs for encoding this value (and any preceeding
+	 eobrun/zerorun) as well as the cost for encoding a demoted token */
+      int cost = tokenize_dctcost(cpi,chroma,coeff,i,dct[i]);
+      int dval = (dct[i]>0 ? dct[i]-1 : dct[i]+1);
+      int j=i;
+      if(dval){
+	/* demoting will not produce a zero. */
+	cost -= tokenize_dctcost(cpi,chroma,coeff,i,dval);
+      }else{
+	/* demoting token will produce a zero. */
+	j=i+1;
+	while((j < BLOCK_SIZE) && !dct[j] ) j++;
+	if(j==BLOCK_SIZE){
+	  cost += tokenize_eobcost(cpi,chroma,i+1);
+	  cost -= tokenize_eobcost(cpi,chroma,coeff);
+	}else{
+	  cost += tokenize_dctcost(cpi,chroma,i+1,j,dct[j]);
+	  cost -= tokenize_dctcost(cpi,chroma,coeff,j,dct[j]);
+	}
+      }
+
+      if(cost>0){
+	/* demoting results in a cheaper token cost.  Is the bit savings worth the added distortion? */
+	int ii = dezigzag_index[i];
+	int od = dct[i]*dequant[i] - origdct[ii];
+	int dd = dval*dequant[i] - origdct[ii];
+	int delta = dd*dd - od*od;
+
+	if(delta < ((cost*cpi->token_lambda)<<4)){
+	  /* we have a winner.  Demote token */
+	  dct[i]=dval;
+
+	  // perhaps a continue here is best; try it later
+
+	  if(dval==0){
+	    if(j==BLOCK_SIZE){
+	      tokenize_mark_run(cpi,chroma,fi,coeff>1,coeff,stack);
+	      coeff = BLOCK_SIZE;
+	      break;
+	    }else{
+	      i=j;
+	      continue;
+	    }
+	  }
+	}
+      }
+	
+      ret = tokenize_dctval(cpi, chroma, fi, coeff, i, dct[i], stack);
+      if(!ret)
+	tokenize_dctval(cpi, chroma, fi, i, i, dct[i], stack);
+      coeff=i+1;
+
     }
   }
 }

Modified: branches/theora-thusnelda/lib/enc/encode.c
===================================================================
--- branches/theora-thusnelda/lib/enc/encode.c	2008-07-10 04:17:49 UTC (rev 15108)
+++ branches/theora-thusnelda/lib/enc/encode.c	2008-07-11 03:07:43 UTC (rev 15109)
@@ -104,7 +104,8 @@
   }
 }
 
-static void ChooseTokenTables (CP_INSTANCE *cpi, int huff[4]) {
+static void ChooseTokenTables (CP_INSTANCE *cpi) {
+  int interp = (cpi->FrameType!=KEY_FRAME);
   int i,plane;
   int best;
   
@@ -112,22 +113,22 @@
 
     /* Work out which table options are best for DC */
     best = cpi->dc_bits[plane][0];
-    huff[plane] = DC_HUFF_OFFSET;
+    cpi->huffchoice[interp][0][plane] = DC_HUFF_OFFSET;
     for ( i = 1; i < DC_HUFF_CHOICES; i++ ) {
       if ( cpi->dc_bits[plane][i] < best ) {
 	best = cpi->dc_bits[plane][i];
-	huff[plane] = i + DC_HUFF_OFFSET;
+	cpi->huffchoice[interp][0][plane] = i + DC_HUFF_OFFSET;
       }
     }
   
     /* Work out which table options are best for AC */
     best = cpi->ac1_bits[plane][0]+cpi->acN_bits[plane][0];
-    huff[plane+2] = AC_HUFF_OFFSET;
+    cpi->huffchoice[interp][1][plane] = AC_HUFF_OFFSET;
     for ( i = 1; i < AC_HUFF_CHOICES; i++ ) {
       int test = cpi->ac1_bits[plane][i] + cpi->acN_bits[plane][i];
       if ( test < best ){
 	best = test;
-	huff[plane+2] = i + AC_HUFF_OFFSET;
+	cpi->huffchoice[interp][1][plane] = i + AC_HUFF_OFFSET;
       }
     }
   }
@@ -162,37 +163,42 @@
   }
 }
 
-static long EncodeTokenList (CP_INSTANCE *cpi, int huff[4]) {
+static long EncodeTokenList (CP_INSTANCE *cpi) {
   int i;
+  int interp = (cpi->FrameType!=KEY_FRAME);
   oggpack_buffer *opb=cpi->oggbuffer;
   long bits0,bits1;
 
   /* DC tokens aren't special, they just come first */
-  oggpackB_write( opb, huff[0] - DC_HUFF_OFFSET, DC_HUFF_CHOICE_BITS );
-  oggpackB_write( opb, huff[1] - DC_HUFF_OFFSET, DC_HUFF_CHOICE_BITS );
+  oggpackB_write( opb, cpi->huffchoice[interp][0][0] - DC_HUFF_OFFSET, DC_HUFF_CHOICE_BITS );
+  oggpackB_write( opb, cpi->huffchoice[interp][0][1] - DC_HUFF_OFFSET, DC_HUFF_CHOICE_BITS );
 
   bits0 = oggpackB_bits(opb);
-  EncodeTokenGroup(cpi, 0,  huff[0], huff[1]);
+  EncodeTokenGroup(cpi, 0,  cpi->huffchoice[interp][0][0], cpi->huffchoice[interp][0][1]);
   bits0 = oggpackB_bits(opb)-bits0;
 
   /* AC tokens */
-  oggpackB_write( opb, huff[2] - AC_HUFF_OFFSET, AC_HUFF_CHOICE_BITS );
-  oggpackB_write( opb, huff[3] - AC_HUFF_OFFSET, AC_HUFF_CHOICE_BITS );
+  oggpackB_write( opb, cpi->huffchoice[interp][1][0] - AC_HUFF_OFFSET, AC_HUFF_CHOICE_BITS );
+  oggpackB_write( opb, cpi->huffchoice[interp][1][1] - AC_HUFF_OFFSET, AC_HUFF_CHOICE_BITS );
 
   bits1 = oggpackB_bits(opb);
   for(i=1;i<=AC_TABLE_2_THRESH;i++)
-    EncodeTokenGroup(cpi, i,  huff[2], huff[3]);
+    EncodeTokenGroup(cpi, i,  cpi->huffchoice[interp][1][0], 
+		     cpi->huffchoice[interp][1][1]);
 
   for(;i<=AC_TABLE_3_THRESH;i++)
-    EncodeTokenGroup(cpi, i,  huff[2]+AC_HUFF_CHOICES, huff[3]+AC_HUFF_CHOICES);
+    EncodeTokenGroup(cpi, i,  cpi->huffchoice[interp][1][0]+AC_HUFF_CHOICES, 
+		     cpi->huffchoice[interp][1][1]+AC_HUFF_CHOICES);
 
   for(;i<=AC_TABLE_4_THRESH;i++)
-    EncodeTokenGroup(cpi, i,  huff[2]+AC_HUFF_CHOICES*2, huff[3]+AC_HUFF_CHOICES*2);
+    EncodeTokenGroup(cpi, i,  cpi->huffchoice[interp][1][0]+AC_HUFF_CHOICES*2, 
+		     cpi->huffchoice[interp][1][1]+AC_HUFF_CHOICES*2);
 
   for(;i<BLOCK_SIZE;i++)
-    EncodeTokenGroup(cpi, i,  huff[2]+AC_HUFF_CHOICES*3, huff[3]+AC_HUFF_CHOICES*3);
+    EncodeTokenGroup(cpi, i,  cpi->huffchoice[interp][1][0]+AC_HUFF_CHOICES*3, 
+		     cpi->huffchoice[interp][1][1]+AC_HUFF_CHOICES*3);
   bits1 = oggpackB_bits(opb)-bits1;
-
+  
   return bits1;
 }
 
@@ -301,16 +307,11 @@
 }
 
 void EncodeData(CP_INSTANCE *cpi){
-  int tokenhuff[4];
   long bits;
 
-  dsp_save_fpu (cpi->dsp);
-
   PredictDC(cpi);
   dct_tokenize_finish(cpi);
 
-  bits = oggpackB_bits(cpi->oggbuffer);
-
   /* Mode and MV data not needed for key frames. */
   if ( cpi->FrameType != KEY_FRAME ){
     PackModes(cpi);
@@ -319,11 +320,11 @@
     bits = oggpackB_bits(cpi->oggbuffer);
   }
 
-  ChooseTokenTables(cpi, tokenhuff);
+  ChooseTokenTables(cpi);
 #ifdef COLLECT_METRICS
-  ModeMetrics(cpi,tokenhuff);
+  ModeMetrics(cpi);
 #endif
-  long bitsDCT = EncodeTokenList(cpi, tokenhuff);
+  long bitsDCT = EncodeTokenList(cpi);
   bits = oggpackB_bits(cpi->oggbuffer);
   
   ReconRefFrames(cpi);

Modified: branches/theora-thusnelda/lib/enc/encoder_toplevel.c
===================================================================
--- branches/theora-thusnelda/lib/enc/encoder_toplevel.c	2008-07-10 04:17:49 UTC (rev 15108)
+++ branches/theora-thusnelda/lib/enc/encoder_toplevel.c	2008-07-11 03:07:43 UTC (rev 15109)
@@ -26,7 +26,7 @@
 #include "dsp.h"
 #include "codec_internal.h"
 
-static void CompressKeyFrame(CP_INSTANCE *cpi){
+static void CompressKeyFrame(CP_INSTANCE *cpi, int recode){
   int i;
 
   oggpackB_reset(cpi->oggbuffer);
@@ -41,13 +41,13 @@
   oggpackB_write(cpi->oggbuffer,0,1);
   
   WriteFrameHeader(cpi);
-  PickModes(cpi,0);
+  PickModes(cpi,recode);
   EncodeData(cpi);
-  
+
   cpi->LastKeyFrame = 1;
 }
 
-static int CompressFrame( CP_INSTANCE *cpi ) {
+static int CompressFrame( CP_INSTANCE *cpi, int recode ) {
   ogg_uint32_t  i;
 
   oggpackB_reset(cpi->oggbuffer);
@@ -60,7 +60,7 @@
   oggpackB_write(cpi->oggbuffer,0,1);
 
   WriteFrameHeader(cpi);
-  if(PickModes( cpi,0 )){
+  if(PickModes( cpi,recode )){
     /* mode analysis thinks this should have been a keyframe; start over and code as a keyframe instead */
 
     oggpackB_reset(cpi->oggbuffer);
@@ -83,6 +83,12 @@
 
     return 0;
   }
+
+  if(cpi->first_inter_frame == 0){
+    cpi->first_inter_frame = 1;
+    CompressFrame(cpi,1);
+    return 0;
+  }
   
   cpi->LastKeyFrame++;
   EncodeData(cpi);
@@ -124,7 +130,8 @@
   cpi->BaseQ = c->quality;
 
   /* temporary while the RD code is only partially complete */
-  cpi->skip_lambda=64;
+  cpi->skip_lambda=24;
+  cpi->token_lambda=24;
   cpi->mv_lambda=0;
 
   /* Set encoder flags. */
@@ -230,10 +237,16 @@
      shift, even if keyframe_auto_p is turned off */
   if(cpi->LastKeyFrame==-1 || cpi->LastKeyFrame >= (ogg_uint32_t)
      cpi->info.keyframe_frequency_force){
-    CompressKeyFrame(cpi);
+
+    CompressKeyFrame(cpi,0);
+
+    /* On first frame, the previous was a initial dry-run to prime
+       feed-forward statistics */
+    if(cpi->CurrentFrame==1)CompressKeyFrame(cpi,1);
+
   } else  {
     /* Compress the frame. */
-    dropped = CompressFrame(cpi);
+    dropped = CompressFrame(cpi,0);
   }
   
   /* Update stats variables. */

Modified: branches/theora-thusnelda/lib/enc/mode.c
===================================================================
--- branches/theora-thusnelda/lib/enc/mode.c	2008-07-10 04:17:49 UTC (rev 15108)
+++ branches/theora-thusnelda/lib/enc/mode.c	2008-07-11 03:07:43 UTC (rev 15109)
@@ -561,7 +561,6 @@
   ogg_int32_t *iq = ps->iq[mode != CODE_INTRA];
   ogg_int16_t buffer[64];
   ogg_int16_t data[64];
-  ogg_int16_t dev[64];
   int bi = cpi->frag_buffer_index[fi];
   int stride = cpi->stride[ps->plane];
   unsigned char *frame_ptr = &cpi->frame[bi];
@@ -666,7 +665,6 @@
 	d = val*dequant[i]-buffer[ii];
 	coded_partial_ssd += d*d;
 	data[i] = val;
-	dev[i] = d;
       }
     }
   }
@@ -713,7 +711,7 @@
   }
 
   /* tokenize */
-  dct_tokenize_AC(cpi, fi, data, fi>=cpi->frag_n[0], stack);
+  dct_tokenize_AC(cpi, fi, data, dequant, buffer, fi>=cpi->frag_n[0], stack);
   
   /* reconstruct */
   while(!data[nonzero] && --nonzero);



More information about the commits mailing list