/******************************************************************** * * * 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-2009 * * by the Xiph.Org Foundation http://www.xiph.org/ * * * ******************************************************************** function: last mod: $Id: tokenize.c 16503 2009-08-22 18:14:02Z giles $ ********************************************************************/ #include #include #include "encint.h" static int oc_make_eob_token(int _run_count){ if(_run_count<4)return OC_DCT_EOB1_TOKEN+_run_count-1; else{ int cat; cat=OC_ILOGNZ_32(_run_count)-3; cat=OC_MINI(cat,3); return OC_DCT_REPEAT_RUN0_TOKEN+cat; } } static int oc_make_eob_token_full(int _run_count,int *_eb){ if(_run_count<4){ *_eb=0; return OC_DCT_EOB1_TOKEN+_run_count-1; } else{ int cat; cat=OC_ILOGNZ_32(_run_count)-3; cat=OC_MINI(cat,3); *_eb=_run_count-OC_BYTE_TABLE32(4,8,16,0,cat); return OC_DCT_REPEAT_RUN0_TOKEN+cat; } } /*Returns the number of blocks ended by an EOB token.*/ static int oc_decode_eob_token(int _token,int _eb){ return (0x20820C41U>>_token*5&0x1F)+_eb; } /*TODO: This is now only used during DCT tokenization, and never for runs; it should be simplified.*/ static int oc_make_dct_token_full(int _zzi,int _zzj,int _val,int *_eb){ int neg; int zero_run; int token; int eb; neg=_val<0; _val=abs(_val); zero_run=_zzj-_zzi; if(zero_run>0){ int adj; /*Implement a minor restriction on stack 1 so that we know during DC fixups that extending a dctrun token from stack 1 will never overflow.*/ adj=_zzi!=1; if(_val<2&&zero_run<17+adj){ if(zero_run<6){ token=OC_DCT_RUN_CAT1A+zero_run-1; eb=neg; } else if(zero_run<10){ token=OC_DCT_RUN_CAT1B; eb=zero_run-6+(neg<<2); } else{ token=OC_DCT_RUN_CAT1C; eb=zero_run-10+(neg<<3); } } else if(_val<4&&zero_run<3+adj){ if(zero_run<2){ token=OC_DCT_RUN_CAT2A; eb=_val-2+(neg<<1); } else{ token=OC_DCT_RUN_CAT2B; eb=zero_run-2+(_val-2<<1)+(neg<<2); } } else{ if(zero_run<9)token=OC_DCT_SHORT_ZRL_TOKEN; else token=OC_DCT_ZRL_TOKEN; eb=zero_run-1; } } else if(_val<3){ token=OC_ONE_TOKEN+(_val-1<<1)+neg; eb=0; } else if(_val<7){ token=OC_DCT_VAL_CAT2+_val-3; eb=neg; } else if(_val<9){ token=OC_DCT_VAL_CAT3; eb=_val-7+(neg<<1); } else if(_val<13){ token=OC_DCT_VAL_CAT4; eb=_val-9+(neg<<2); } else if(_val<21){ token=OC_DCT_VAL_CAT5; eb=_val-13+(neg<<3); } else if(_val<37){ token=OC_DCT_VAL_CAT6; eb=_val-21+(neg<<4); } else if(_val<69){ token=OC_DCT_VAL_CAT7; eb=_val-37+(neg<<5); } else{ token=OC_DCT_VAL_CAT8; eb=_val-69+(neg<<9); } *_eb=eb; return token; } /*Token logging to allow a few fragments of efficient rollback. Late SKIP analysis is tied up in the tokenization process, so we need to be able to undo a fragment's tokens on a whim.*/ 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 }; static int oc_token_bits(oc_enc_ctx *_enc,int _huffi,int _zzi,int _token){ return _enc->huff_codes[_huffi+OC_ZZI_HUFF_OFFSET[_zzi]][_token].nbits +OC_DCT_TOKEN_EXTRA_BITS[_token]; } static void oc_enc_tokenlog_checkpoint(oc_enc_ctx *_enc, oc_token_checkpoint *_cp,int _pli,int _zzi){ _cp->pli=_pli; _cp->zzi=_zzi; _cp->eob_run=_enc->eob_run[_pli][_zzi]; _cp->ndct_tokens=_enc->ndct_tokens[_pli][_zzi]; } void oc_enc_tokenlog_rollback(oc_enc_ctx *_enc, const oc_token_checkpoint *_stack,int _n){ int i; for(i=_n;i-->0;){ int pli; int zzi; pli=_stack[i].pli; zzi=_stack[i].zzi; _enc->eob_run[pli][zzi]=_stack[i].eob_run; _enc->ndct_tokens[pli][zzi]=_stack[i].ndct_tokens; } } static void oc_enc_token_log(oc_enc_ctx *_enc, int _pli,int _zzi,int _token,int _eb){ ptrdiff_t ti; ti=_enc->ndct_tokens[_pli][_zzi]++; _enc->dct_tokens[_pli][_zzi][ti]=(unsigned char)_token; _enc->extra_bits[_pli][_zzi][ti]=(ogg_uint16_t)_eb; } static void oc_enc_eob_log(oc_enc_ctx *_enc, int _pli,int _zzi,int _run_count){ int token; int eb; token=oc_make_eob_token_full(_run_count,&eb); oc_enc_token_log(_enc,_pli,_zzi,token,eb); } void oc_enc_tokenize_start(oc_enc_ctx *_enc){ memset(_enc->ndct_tokens,0,sizeof(_enc->ndct_tokens)); memset(_enc->eob_run,0,sizeof(_enc->eob_run)); memset(_enc->dct_token_offs,0,sizeof(_enc->dct_token_offs)); memset(_enc->dc_pred_last,0,sizeof(_enc->dc_pred_last)); } typedef struct oc_quant_token oc_quant_token; /*A single node in the Viterbi trellis. We maintain up to 2 of these per coefficient: - A token to code if the value is zero (EOB, zero run, or combo token). - A token to code if the value is not zero (DCT value token).*/ struct oc_quant_token{ unsigned char next; signed char token; ogg_int16_t eb; ogg_uint32_t cost; int bits; int qc; }; /*Tokenizes the AC coefficients, possibly adjusting the quantization, and then dequantizes and de-zig-zags the result. The DC coefficient is not preserved; it should be restored by the caller.*/ int oc_enc_tokenize_ac(oc_enc_ctx *_enc,int _pli,ptrdiff_t _fragi, ogg_int16_t *_qdct,const ogg_uint16_t *_dequant,const ogg_int16_t *_dct, int _zzi,oc_token_checkpoint **_stack,int _acmin){ oc_token_checkpoint *stack; ogg_int64_t zflags; ogg_int64_t nzflags; ogg_int64_t best_flags; ogg_uint32_t d2_accum[64]; oc_quant_token tokens[64][2]; ogg_uint16_t *eob_run; const unsigned char *dct_fzig_zag; ogg_uint32_t cost; int bits; int eob; int token; int eb; int next; int huffi; int zzi; int ti; int zzj; int qc; huffi=_enc->huff_idxs[_enc->state.frame_type][1][_pli+1>>1]; eob_run=_enc->eob_run[_pli]; memset(tokens[0],0,sizeof(tokens[0])); best_flags=nzflags=0; zflags=1; d2_accum[0]=0; zzj=64; for(zzi=OC_MINI(_zzi,63);zzi>0;zzi--){ ogg_int32_t lambda; ogg_uint32_t best_cost; int best_bits=best_bits; int best_next=best_next; int best_token=best_token; int best_eb=best_eb; int best_qc=best_qc; int flush_bits; ogg_uint32_t d2; int dq; int e; int c; int s; int tj; lambda=_enc->lambda; qc=_qdct[zzi]; s=-(qc<0); qc=qc+s^s; c=_dct[OC_FZIG_ZAG[zzi]]; if(qc<=1){ ogg_uint32_t sum_d2; int nzeros; int dc_reserve; /*The hard case: try a zero run.*/ if(!qc){ /*Skip runs that are already quantized to zeros. If we considered each zero coefficient in turn, we might theoretically find a better way to partition long zero runs (e.g., a run of > 17 zeros followed by a 1 might be better coded as a short zero run followed by a combo token, rather than the longer zero token followed by a 1 value token), but zeros are so common that this becomes very computationally expensive (quadratic instead of linear in the number of coefficients), for a marginal gain.*/ while(zzi>1&&!_qdct[zzi-1])zzi--; /*The distortion of coefficients originally quantized to zero is treated as zero (since we'll never quantize them to anything else).*/ d2=0; } else{ c=c+s^s; d2=c*(ogg_int32_t)c; } eob=eob_run[zzi]; nzeros=zzj-zzi; zzj&=63; sum_d2=d2+d2_accum[zzj]; d2_accum[zzi]=sum_d2; flush_bits=eob>0?oc_token_bits(_enc,huffi,zzi,oc_make_eob_token(eob)):0; /*We reserve 1 spot for combo run tokens that start in the 1st AC stack to ensure they can be extended to include the DC coefficient if necessary; this greatly simplifies stack-rewriting later on.*/ dc_reserve=zzi+62>>6; best_cost=0xFFFFFFFF; for(;;){ if(nzflags>>zzj&1){ int cat; int val; int val_s; int zzk; int tk; next=tokens[zzj][1].next; tk=next&1; zzk=next>>1; /*Try a pure zero run to this point.*/ cat=nzeros+55>>6; token=OC_DCT_SHORT_ZRL_TOKEN+cat; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); d2=sum_d2-d2_accum[zzj]; cost=d2+lambda*bits+tokens[zzj][1].cost; if(cost<=best_cost){ best_next=(zzj<<1)+1; best_token=token; best_eb=nzeros-1; best_cost=cost; best_bits=bits+tokens[zzj][1].bits; best_qc=0; } if(nzeros<16+dc_reserve){ val=_qdct[zzj]; val_s=-(val<0); val=val+val_s^val_s; if(val<=2){ /*Try a +/- 1 combo token.*/ if(nzeros<6){ token=OC_DCT_RUN_CAT1A+nzeros-1; eb=-val_s; } else{ cat=nzeros+54>>6; token=OC_DCT_RUN_CAT1B+cat; eb=(-val_s<>1; token=OC_DCT_RUN_CAT2A+cat; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); val=2+((val+val_s^val_s)>2); e=(_dct[OC_FZIG_ZAG[zzj]]+val_s^val_s)-_dequant[zzj]*val; d2=e*(ogg_int32_t)e+sum_d2-d2_accum[zzj]; cost=d2+lambda*bits+tokens[zzk][tk].cost; if(cost<=best_cost){ best_cost=cost; best_bits=bits+tokens[zzk][tk].bits; best_next=next; best_token=token; best_eb=(-val_s<<1+cat)+(val-2<>1); best_qc=val+val_s^val_s; } } } /*zzj can't be coded as a zero, so stop trying to extend the run.*/ if(!(zflags>>zzj&1))break; } /*We could try to consider _all_ potentially non-zero coefficients, but if we already found a bunch of them not worth coding, it's fairly unlikely they would now be worth coding from this position; skipping them saves a lot of work.*/ zzj=(tokens[zzj][0].next>>1)-(tokens[zzj][0].qc!=0)&63; if(zzj==0){ /*We made it all the way to the end of the block; try an EOB token.*/ if(eob<4095){ bits=oc_token_bits(_enc,huffi,zzi,oc_make_eob_token(eob+1)) -flush_bits; } else bits=oc_token_bits(_enc,huffi,zzi,OC_DCT_EOB1_TOKEN); cost=sum_d2+bits*lambda; /*If the best route so far is still a pure zero run to the end of the block, force coding it as an EOB. Even if it's not optimal for this block, it has a good chance of getting combined with an EOB token from subsequent blocks, saving bits overall.*/ if(cost<=best_cost||best_token<=OC_DCT_ZRL_TOKEN&&zzi+best_eb==63){ best_next=0; /*This token is just a marker; in reality we may not emit any tokens, but update eob_run[] instead.*/ best_token=OC_DCT_EOB1_TOKEN; best_eb=0; best_cost=cost; best_bits=bits; best_qc=0; } break; } nzeros=zzj-zzi; } tokens[zzi][0].next=(unsigned char)best_next; tokens[zzi][0].token=(signed char)best_token; tokens[zzi][0].eb=(ogg_int16_t)best_eb; tokens[zzi][0].cost=best_cost; tokens[zzi][0].bits=best_bits; tokens[zzi][0].qc=best_qc; zflags|=(ogg_int64_t)1<>zzj&1; next=(zzj<<1)+tj; tokens[zzi][1].next=(unsigned char)next; tokens[zzi][1].token=(signed char)token; tokens[zzi][1].eb=0; tokens[zzi][1].cost=d2+lambda*bits+tokens[zzj][tj].cost; tokens[zzi][1].bits=bits+tokens[zzj][tj].bits; tokens[zzi][1].qc=1+s^s; nzflags|=(ogg_int64_t)1<0?oc_token_bits(_enc,huffi,zzi,oc_make_eob_token(eob)):0; if(qc<=2){ e=2*dq-c; d2=e*(ogg_int32_t)e; best_token=OC_TWO_TOKEN-s; best_bits=flush_bits+oc_token_bits(_enc,huffi,zzi,best_token); best_cost=d2+lambda*best_bits; e-=dq; d2=e*(ogg_int32_t)e; token=OC_ONE_TOKEN-s; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); cost=d2+lambda*bits; if(cost<=best_cost){ best_token=token; best_bits=bits; best_cost=cost; qc--; } best_eb=0; } else if(qc<=3){ e=3*dq-c; d2=e*(ogg_int32_t)e; best_token=OC_DCT_VAL_CAT2; best_eb=-s; best_bits=flush_bits+oc_token_bits(_enc,huffi,zzi,best_token); best_cost=d2+lambda*best_bits; e-=dq; d2=e*(ogg_int32_t)e; token=OC_TWO_TOKEN-s; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); cost=d2+lambda*bits; if(cost<=best_cost){ best_token=token; best_eb=0; best_bits=bits; best_cost=cost; qc--; } } else if(qc<=6){ e=qc*dq-c; d2=e*(ogg_int32_t)e; best_token=OC_DCT_VAL_CAT2+qc-3; best_eb=-s; best_bits=flush_bits+oc_token_bits(_enc,huffi,zzi,best_token); best_cost=d2+lambda*best_bits; e-=dq; d2=e*(ogg_int32_t)e; token=best_token-1; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); cost=d2+lambda*bits; if(cost<=best_cost){ best_token=token; best_bits=bits; best_cost=cost; qc--; } } else if(qc<=8){ e=qc*dq-c; d2=e*(ogg_int32_t)e; best_token=OC_DCT_VAL_CAT3; best_eb=(-s<<1)+qc-7; best_bits=flush_bits+oc_token_bits(_enc,huffi,zzi,best_token); best_cost=d2+lambda*best_bits; e=6*dq-c; d2=e*(ogg_int32_t)e; token=OC_DCT_VAL_CAT2+3; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); cost=d2+lambda*bits; if(cost<=best_cost){ best_token=token; best_eb=-s; best_bits=bits; best_cost=cost; qc=6; } } else if(qc<=12){ e=qc*dq-c; d2=e*(ogg_int32_t)e; best_token=OC_DCT_VAL_CAT4; best_eb=(-s<<2)+qc-9; best_bits=flush_bits+oc_token_bits(_enc,huffi,zzi,best_token); best_cost=d2+lambda*best_bits; e=8*dq-c; d2=e*(ogg_int32_t)e; token=best_token-1; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); cost=d2+lambda*bits; if(cost<=best_cost){ best_token=token; best_eb=(-s<<1)+1; best_bits=bits; best_cost=cost; qc=8; } } else if(qc<=20){ e=qc*dq-c; d2=e*(ogg_int32_t)e; best_token=OC_DCT_VAL_CAT5; best_eb=(-s<<3)+qc-13; best_bits=flush_bits+oc_token_bits(_enc,huffi,zzi,best_token); best_cost=d2+lambda*best_bits; e=12*dq-c; d2=e*(ogg_int32_t)e; token=best_token-1; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); cost=d2+lambda*bits; if(cost<=best_cost){ best_token=token; best_eb=(-s<<2)+3; best_bits=bits; best_cost=cost; qc=12; } } else if(qc<=36){ e=qc*dq-c; d2=e*(ogg_int32_t)e; best_token=OC_DCT_VAL_CAT6; best_eb=(-s<<4)+qc-21; best_bits=flush_bits+oc_token_bits(_enc,huffi,zzi,best_token); best_cost=d2+lambda*best_bits; e=20*dq-c; d2=e*(ogg_int32_t)e; token=best_token-1; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); cost=d2+lambda*bits; if(cost<=best_cost){ best_token=token; best_eb=(-s<<3)+7; best_bits=bits; best_cost=cost; qc=20; } } else if(qc<=68){ e=qc*dq-c; d2=e*(ogg_int32_t)e; best_token=OC_DCT_VAL_CAT7; best_eb=(-s<<5)+qc-37; best_bits=flush_bits+oc_token_bits(_enc,huffi,zzi,best_token); best_cost=d2+lambda*best_bits; e=36*dq-c; d2=e*(ogg_int32_t)e; token=best_token-1; bits=flush_bits+oc_token_bits(_enc,huffi,zzi,token); cost=d2+lambda*bits; if(cost>zzj&1; next=(zzj<<1)+tj; tokens[zzi][1].next=(unsigned char)next; tokens[zzi][1].token=(signed char)best_token; tokens[zzi][1].eb=best_eb; tokens[zzi][1].cost=best_cost+tokens[zzj][tj].cost; tokens[zzi][1].bits=best_bits+tokens[zzj][tj].bits; tokens[zzi][1].qc=qc+s^s; nzflags|=(ogg_int64_t)1<state.opt_data.dct_fzig_zag; zzi=1; ti=best_flags>>1&1; bits=tokens[zzi][ti].bits; do{ oc_enc_tokenlog_checkpoint(_enc,stack++,_pli,zzi); eob=eob_run[zzi]; if(tokens[zzi][ti].token=4095){ oc_enc_eob_log(_enc,_pli,zzi,eob); eob=0; } eob_run[zzi]=eob; /*We don't include the actual EOB cost for this block in the return value. It will be paid for by the fragment that terminates the EOB run.*/ bits-=tokens[zzi][ti].bits; zzi=_zzi; break; } /*Emit pending EOB run if any.*/ if(eob>0){ oc_enc_eob_log(_enc,_pli,zzi,eob); eob_run[zzi]=0; } oc_enc_token_log(_enc,_pli,zzi,tokens[zzi][ti].token,tokens[zzi][ti].eb); next=tokens[zzi][ti].next; qc=tokens[zzi][ti].qc; zzj=(next>>1)-1&63; /*TODO: It may be worth saving the dequantized coefficient in the trellis above; we had to compute it to measure the error anyway.*/ _qdct[dct_fzig_zag[zzj]]=(ogg_int16_t)(qc*(int)_dequant[zzj]); zzi=next>>1; ti=next&1; } while(zzi); *_stack=stack; return bits; } void oc_enc_pred_dc_frag_rows(oc_enc_ctx *_enc, int _pli,int _fragy0,int _frag_yend){ const oc_fragment_plane *fplane; const oc_fragment *frags; ogg_int16_t *frag_dc; ptrdiff_t fragi; int *pred_last; int nhfrags; int fragx; int fragy; fplane=_enc->state.fplanes+_pli; frags=_enc->state.frags; frag_dc=_enc->frag_dc; pred_last=_enc->dc_pred_last[_pli]; nhfrags=fplane->nhfrags; fragi=fplane->froffset+_fragy0*nhfrags; for(fragy=_fragy0;fragy<_frag_yend;fragy++){ if(fragy==0){ /*For the first row, all of the cases reduce to just using the previous predictor for the same reference frame.*/ for(fragx=0;fragx=nhfrags)ur_ref=-1; else{ ur_ref=u_frags[fragi+1].coded? OC_FRAME_FOR_MODE(u_frags[fragi+1].mb_mode):-1; } if(frags[fragi].coded){ int pred; int ref; ref=OC_FRAME_FOR_MODE(frags[fragi].mb_mode); /*We break out a separate case based on which of our neighbors use the same reference frames. This is somewhat faster than trying to make a generic case which handles all of them, since it reduces lots of poorly predicted jumps to one switch statement, and also lets a number of the multiplications be optimized out by strength reduction.*/ switch((l_ref==ref)|(ul_ref==ref)<<1| (u_ref==ref)<<2|(ur_ref==ref)<<3){ default:pred=pred_last[ref];break; case 1: case 3:pred=frags[fragi-1].dc;break; case 2:pred=u_frags[fragi-1].dc;break; case 4: case 6: case 12:pred=u_frags[fragi].dc;break; case 5:pred=(frags[fragi-1].dc+u_frags[fragi].dc)/2;break; case 8:pred=u_frags[fragi+1].dc;break; case 9: case 11: case 13:{ pred=(75*frags[fragi-1].dc+53*u_frags[fragi+1].dc)/128; }break; case 10:pred=(u_frags[fragi-1].dc+u_frags[fragi+1].dc)/2;break; case 14:{ pred=(3*(u_frags[fragi-1].dc+u_frags[fragi+1].dc) +10*u_frags[fragi].dc)/16; }break; case 7: case 15:{ int p0; int p1; int p2; p0=frags[fragi-1].dc; p1=u_frags[fragi-1].dc; p2=u_frags[fragi].dc; pred=(29*(p0+p2)-26*p1)/32; if(abs(pred-p2)>128)pred=p2; else if(abs(pred-p0)>128)pred=p0; else if(abs(pred-p1)>128)pred=p1; }break; } frag_dc[fragi]=(ogg_int16_t)(frags[fragi].dc-pred); pred_last[ref]=frags[fragi].dc; l_ref=ref; } else l_ref=-1; ul_ref=u_ref; u_ref=ur_ref; } } } } void oc_enc_tokenize_dc_frag_list(oc_enc_ctx *_enc,int _pli, const ptrdiff_t *_coded_fragis,ptrdiff_t _ncoded_fragis, int _prev_ndct_tokens1,int _prev_eob_run1){ const ogg_int16_t *frag_dc; ptrdiff_t fragii; unsigned char *dct_tokens0; unsigned char *dct_tokens1; ogg_uint16_t *extra_bits0; ogg_uint16_t *extra_bits1; ptrdiff_t ti0; ptrdiff_t ti1r; ptrdiff_t ti1w; int eob_run0; int eob_run1; int neobs1; int token; int eb; int token1=token1; int eb1=eb1; /*Return immediately if there are no coded fragments; otherwise we'd flush any trailing EOB run into the AC 1 list and never read it back out.*/ if(_ncoded_fragis<=0)return; frag_dc=_enc->frag_dc; dct_tokens0=_enc->dct_tokens[_pli][0]; dct_tokens1=_enc->dct_tokens[_pli][1]; extra_bits0=_enc->extra_bits[_pli][0]; extra_bits1=_enc->extra_bits[_pli][1]; ti0=_enc->ndct_tokens[_pli][0]; ti1w=ti1r=_prev_ndct_tokens1; eob_run0=_enc->eob_run[_pli][0]; /*Flush any trailing EOB run for the 1st AC coefficient. This is needed to allow us to track tokens to the end of the list.*/ eob_run1=_enc->eob_run[_pli][1]; if(eob_run1>0)oc_enc_eob_log(_enc,_pli,1,eob_run1); /*If there was an active EOB run at the start of the 1st AC stack, read it in and decode it.*/ if(_prev_eob_run1>0){ token1=dct_tokens1[ti1r]; eb1=extra_bits1[ti1r]; ti1r++; eob_run1=oc_decode_eob_token(token1,eb1); /*Consume the portion of the run that came before these fragments.*/ neobs1=eob_run1-_prev_eob_run1; } else eob_run1=neobs1=0; for(fragii=0;fragii<_ncoded_fragis;fragii++){ int val; /*All tokens in the 1st AC coefficient stack are regenerated as the DC coefficients are produced. This can be done in-place; stack 1 cannot get larger.*/ if(!neobs1){ /*There's no active EOB run in stack 1; read the next token.*/ token1=dct_tokens1[ti1r]; eb1=extra_bits1[ti1r]; ti1r++; if(token10){ token=oc_make_eob_token_full(eob_run0,&eb); dct_tokens0[ti0]=(unsigned char)token; extra_bits0[ti0]=(ogg_uint16_t)eb; ti0++; eob_run0=0; } token=oc_make_dct_token_full(0,0,val,&eb); dct_tokens0[ti0]=(unsigned char)token; extra_bits0[ti0]=(ogg_uint16_t)eb; ti0++; } else{ /*Zero DC value; that means the entry in stack 1 might need to be coded from stack 0. This requires a stack 1 fixup.*/ if(neobs1>0){ /*We're in the middle of an active EOB run in stack 1. Move it to stack 0.*/ if(++eob_run0>=4095){ token=oc_make_eob_token_full(eob_run0,&eb); dct_tokens0[ti0]=(unsigned char)token; extra_bits0[ti0]=(ogg_uint16_t)eb; ti0++; eob_run0=0; } eob_run1--; } else{ /*No active EOB run in stack 1, so we can't extend one in stack 0. Flush it if we've got it.*/ if(eob_run0>0){ token=oc_make_eob_token_full(eob_run0,&eb); dct_tokens0[ti0]=(unsigned char)token; extra_bits0[ti0]=(ogg_uint16_t)eb; ti0++; eob_run0=0; } /*Stack 1 token is one of: a pure zero run token, a single coefficient token, or a zero run/coefficient combo token. A zero run token is expanded and moved to token stack 0, and the stack 1 entry dropped. A single coefficient value may be transformed into combo token that is moved to stack 0, or if it cannot be combined, it is left alone and a single length-1 zero run is emitted in stack 0. A combo token is extended and moved to stack 0. During AC coding, we restrict the run lengths on combo tokens for stack 1 to guarantee we can extend them.*/ switch(token1){ case OC_DCT_SHORT_ZRL_TOKEN:{ if(eb1<7){ dct_tokens0[ti0]=OC_DCT_SHORT_ZRL_TOKEN; extra_bits0[ti0]=(ogg_uint16_t)(eb1+1); ti0++; /*Don't write the AC coefficient back out.*/ continue; } /*Fall through.*/ } case OC_DCT_ZRL_TOKEN:{ dct_tokens0[ti0]=OC_DCT_ZRL_TOKEN; extra_bits0[ti0]=(ogg_uint16_t)(eb1+1); ti0++; /*Don't write the AC coefficient back out.*/ }continue; case OC_ONE_TOKEN: case OC_MINUS_ONE_TOKEN:{ dct_tokens0[ti0]=OC_DCT_RUN_CAT1A; extra_bits0[ti0]=(ogg_uint16_t)(token1-OC_ONE_TOKEN); ti0++; /*Don't write the AC coefficient back out.*/ }continue; case OC_TWO_TOKEN: case OC_MINUS_TWO_TOKEN:{ dct_tokens0[ti0]=OC_DCT_RUN_CAT2A; extra_bits0[ti0]=(ogg_uint16_t)(token1-OC_TWO_TOKEN<<1); ti0++; /*Don't write the AC coefficient back out.*/ }continue; case OC_DCT_VAL_CAT2:{ dct_tokens0[ti0]=OC_DCT_RUN_CAT2A; extra_bits0[ti0]=(ogg_uint16_t)((eb1<<1)+1); ti0++; /*Don't write the AC coefficient back out.*/ }continue; case OC_DCT_RUN_CAT1A: case OC_DCT_RUN_CAT1A+1: case OC_DCT_RUN_CAT1A+2: case OC_DCT_RUN_CAT1A+3:{ dct_tokens0[ti0]=(unsigned char)(token1+1); extra_bits0[ti0]=(ogg_uint16_t)eb1; ti0++; /*Don't write the AC coefficient back out.*/ }continue; case OC_DCT_RUN_CAT1A+4:{ dct_tokens0[ti0]=OC_DCT_RUN_CAT1B; extra_bits0[ti0]=(ogg_uint16_t)(eb1<<2); ti0++; /*Don't write the AC coefficient back out.*/ }continue; case OC_DCT_RUN_CAT1B:{ if((eb1&3)<3){ dct_tokens0[ti0]=OC_DCT_RUN_CAT1B; extra_bits0[ti0]=(ogg_uint16_t)(eb1+1); ti0++; /*Don't write the AC coefficient back out.*/ continue; } eb1=((eb1&4)<<1)-1; /*Fall through.*/ } case OC_DCT_RUN_CAT1C:{ dct_tokens0[ti0]=OC_DCT_RUN_CAT1C; extra_bits0[ti0]=(ogg_uint16_t)(eb1+1); ti0++; /*Don't write the AC coefficient back out.*/ }continue; case OC_DCT_RUN_CAT2A:{ eb1=(eb1<<1)-1; /*Fall through.*/ } case OC_DCT_RUN_CAT2B:{ dct_tokens0[ti0]=OC_DCT_RUN_CAT2B; extra_bits0[ti0]=(ogg_uint16_t)(eb1+1); ti0++; /*Don't write the AC coefficient back out.*/ }continue; } /*We can't merge tokens, write a short zero run and keep going.*/ dct_tokens0[ti0]=OC_DCT_SHORT_ZRL_TOKEN; extra_bits0[ti0]=0; ti0++; } } if(!neobs1){ /*Flush any (inactive) EOB run.*/ if(eob_run1>0){ token=oc_make_eob_token_full(eob_run1,&eb); dct_tokens1[ti1w]=(unsigned char)token; extra_bits1[ti1w]=(ogg_uint16_t)eb; ti1w++; eob_run1=0; } /*There's no active EOB run, so log the current token.*/ dct_tokens1[ti1w]=(unsigned char)token1; extra_bits1[ti1w]=(ogg_uint16_t)eb1; ti1w++; } else{ /*Otherwise consume one EOB from the current run.*/ neobs1--; /*If we have more than 4095 EOBs outstanding in stack1, flush the run.*/ if(eob_run1-neobs1>=4095){ token=oc_make_eob_token_full(4095,&eb); dct_tokens1[ti1w]=(unsigned char)token; extra_bits1[ti1w]=(ogg_uint16_t)eb; ti1w++; eob_run1-=4095; } } } /*Save the current state.*/ _enc->ndct_tokens[_pli][0]=ti0; _enc->ndct_tokens[_pli][1]=ti1w; _enc->eob_run[_pli][0]=eob_run0; _enc->eob_run[_pli][1]=eob_run1; } /*Final EOB run welding.*/ void oc_enc_tokenize_finish(oc_enc_ctx *_enc){ int pli; int zzi; /*Emit final EOB runs.*/ for(pli=0;pli<3;pli++)for(zzi=0;zzi<64;zzi++){ int eob_run; eob_run=_enc->eob_run[pli][zzi]; if(eob_run>0)oc_enc_eob_log(_enc,pli,zzi,eob_run); } /*Merge the final EOB run of one token list with the start of the next, if possible.*/ for(zzi=0;zzi<64;zzi++)for(pli=0;pli<3;pli++){ int old_tok1; int old_tok2; int old_eb1; int old_eb2; int new_tok; int new_eb; int zzj; int plj; ptrdiff_t ti=ti; int run_count; /*Make sure this coefficient has tokens at all.*/ if(_enc->ndct_tokens[pli][zzi]<=0)continue; /*Ensure the first token is an EOB run.*/ old_tok2=_enc->dct_tokens[pli][zzi][0]; if(old_tok2>=OC_NDCT_EOB_TOKEN_MAX)continue; /*Search for a previous coefficient that has any tokens at all.*/ old_tok1=OC_NDCT_EOB_TOKEN_MAX; for(zzj=zzi,plj=pli;zzj>=0;zzj--){ while(plj-->0){ ti=_enc->ndct_tokens[plj][zzj]-1; if(ti>=_enc->dct_token_offs[plj][zzj]){ old_tok1=_enc->dct_tokens[plj][zzj][ti]; break; } } if(plj>=0)break; plj=3; } /*Ensure its last token was an EOB run.*/ if(old_tok1>=OC_NDCT_EOB_TOKEN_MAX)continue; /*Pull off the associated extra bits, if any, and decode the runs.*/ old_eb1=_enc->extra_bits[plj][zzj][ti]; old_eb2=_enc->extra_bits[pli][zzi][0]; run_count=oc_decode_eob_token(old_tok1,old_eb1) +oc_decode_eob_token(old_tok2,old_eb2); /*We can't possibly combine these into one run. It might be possible to split them more optimally, but we'll just leave them as-is.*/ if(run_count>=4096)continue; /*We CAN combine them into one run.*/ new_tok=oc_make_eob_token_full(run_count,&new_eb); _enc->dct_tokens[plj][zzj][ti]=(unsigned char)new_tok; _enc->extra_bits[plj][zzj][ti]=(ogg_uint16_t)new_eb; _enc->dct_token_offs[pli][zzi]++; } }