[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