X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Fbitrate.c;h=e261bb1737ac57187485def1823a9ade858729d9;hb=e5b1378996dba3ea82fb35403cb1f0bbff19495c;hp=3c7eae385ba3367e37f71940b207c8ec2915c9ac;hpb=424741874e8395e294a37283f0cfbb73958b1110;p=platform%2Fupstream%2Flibvorbis.git diff --git a/lib/bitrate.c b/lib/bitrate.c index 3c7eae3..e261bb1 100644 --- a/lib/bitrate.c +++ b/lib/bitrate.c @@ -5,580 +5,249 @@ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * - * by the XIPHOPHORUS Company http://www.xiph.org/ * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * + * by the Xiph.Org Foundation http://www.xiph.org/ * * * ******************************************************************** function: bitrate tracking and management - last mod: $Id: bitrate.c,v 1.3 2001/12/14 07:21:16 xiphmont Exp $ + last mod: $Id$ ********************************************************************/ -#include #include -#include #include #include #include #include "vorbis/codec.h" #include "codec_internal.h" #include "os.h" +#include "misc.h" #include "bitrate.h" -#define BINBITS(pos,bin) ((bin)>0?bm->queue_binned[(pos)*bins+(bin)-1]:0) -#define LIMITBITS(pos,bin) ((bin)>-bins?\ - bm->minmax_binstack[(pos)*bins*2+((bin)+bins)-1]:0) +/* compute bitrate tracking setup */ +void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){ + codec_setup_info *ci=vi->codec_setup; + bitrate_manager_info *bi=&ci->bi; -static long LACING_ADJUST(long bits){ - int addto=((bits+7)/8+1)/256+1; - return( ((bits+7)/8+addto)*8 ); -} + memset(bm,0,sizeof(*bm)); -static double floater_interpolate(bitrate_manager_state *bm,vorbis_info *vi, - double desired_rate){ - int bin=bm->avgfloat*BITTRACK_DIVISOR-1.; - double lobitrate; - double hibitrate; - - lobitrate=(double)(bin==0?0:bm->avg_binacc[bin-1])/bm->avg_sampleacc*vi->rate; - while(lobitrate>desired_rate && bin>0){ - bin--; - lobitrate=(double)(bin==0?0:bm->avg_binacc[bin-1])/bm->avg_sampleacc*vi->rate; - } + if(bi && (bi->reservoir_bits>0)){ + long ratesamples=vi->rate; + int halfsamples=ci->blocksizes[0]>>1; - hibitrate=(double)(bin>=bm->queue_bins?bm->avg_binacc[bm->queue_bins-1]: - bm->avg_binacc[bin])/bm->avg_sampleacc*vi->rate; - while(hibitratequeue_bins){ - bin++; - if(binqueue_bins) - hibitrate=(double)bm->avg_binacc[bin]/bm->avg_sampleacc*vi->rate; - } + bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0]; + bm->managed=1; - /* interpolate */ - if(bin==bm->queue_bins){ - return bin/(double)BITTRACK_DIVISOR; - }else{ - double delta=(desired_rate-lobitrate)/(hibitrate-lobitrate); - return (bin+delta)/(double)BITTRACK_DIVISOR; - } -} + bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples); + bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples); + bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples); -/* try out a new limit */ -static long limit_sum(bitrate_manager_state *bm,int limit){ - int i=bm->minmax_stackptr; - long acc=bm->minmax_acctotal; - long bins=bm->queue_bins; - - acc-=LIMITBITS(i,0); - acc+=LIMITBITS(i,limit); - - while(i-->0){ - if(bm->minmax_limitstack[i]<=limit)break; - acc-=LIMITBITS(i,bm->minmax_limitstack[i]); - acc+=LIMITBITS(i,limit); - } - return(acc); -} + bm->avgfloat=PACKETBLOBS/2; -/* compute bitrate tracking setup, allocate circular packet size queue */ -void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){ - int i; - codec_setup_info *ci=vi->codec_setup; - bitrate_manager_info *bi=&ci->bi; - long maxlatency; + /* not a necessary fix, but one that leads to a more balanced + typical initialization */ + { + long desired_fill=bi->reservoir_bits*bi->reservoir_bias; + bm->minmax_reservoir=desired_fill; + bm->avg_reservoir=desired_fill; + } - memset(bm,0,sizeof(*bm)); - - if(bi){ - - bm->avg_sampledesired=bi->queue_avg_time*vi->rate; - bm->avg_centerdesired=bi->queue_avg_time*vi->rate*bi->queue_avg_center; - bm->minmax_sampledesired=bi->queue_minmax_time*vi->rate; - - /* first find the max possible needed queue size */ - maxlatency=max(bm->avg_sampledesired-bm->avg_centerdesired, - bm->minmax_sampledesired)+bm->avg_centerdesired; - - if(maxlatency>0 && - (bi->queue_avgmin>0 || bi->queue_avgmax>0 || bi->queue_hardmax>0 || - bi->queue_hardmin>0)){ - long maxpackets=maxlatency/(ci->blocksizes[0]>>1)+3; - long bins=BITTRACK_DIVISOR*ci->passlimit[ci->coupling_passes-1]; - - bm->queue_size=maxpackets; - bm->queue_bins=bins; - bm->queue_binned=_ogg_malloc(maxpackets*bins*sizeof(*bm->queue_binned)); - bm->queue_actual=_ogg_malloc(maxpackets*sizeof(*bm->queue_actual)); - - if((bi->queue_avgmin>0 || bi->queue_avgmax>0) && - bi->queue_avg_time>0){ - - bm->avg_binacc=_ogg_malloc(bins*sizeof(*bm->avg_binacc)); - bm->avgfloat=bi->avgfloat_initial; - - - }else{ - bm->avg_tail= -1; - } - - if((bi->queue_hardmin>0 || bi->queue_hardmax>0) && - bi->queue_minmax_time>0){ - - bm->minmax_binstack=_ogg_malloc((bins+1)*bins*2* - sizeof(bm->minmax_binstack)); - bm->minmax_posstack=_ogg_malloc((bins+1)* - sizeof(bm->minmax_posstack)); - bm->minmax_limitstack=_ogg_malloc((bins+1)* - sizeof(bm->minmax_limitstack)); - }else{ - bm->minmax_tail= -1; - } - - /* space for the packet queueing */ - bm->queue_packet_buffers=calloc(maxpackets,sizeof(*bm->queue_packet_buffers)); - bm->queue_packets=calloc(maxpackets,sizeof(*bm->queue_packets)); - for(i=0;iqueue_packet_buffers+i); - - }else{ - bm->queue_packet_buffers=calloc(1,sizeof(*bm->queue_packet_buffers)); - bm->queue_packets=calloc(1,sizeof(*bm->queue_packets)); - oggpack_writeinit(bm->queue_packet_buffers); - } } } void vorbis_bitrate_clear(bitrate_manager_state *bm){ - int i; - if(bm){ - if(bm->queue_binned)_ogg_free(bm->queue_binned); - if(bm->queue_actual)_ogg_free(bm->queue_actual); - if(bm->avg_binacc)_ogg_free(bm->avg_binacc); - if(bm->minmax_binstack)_ogg_free(bm->minmax_binstack); - if(bm->minmax_posstack)_ogg_free(bm->minmax_posstack); - if(bm->minmax_limitstack)_ogg_free(bm->minmax_limitstack); - if(bm->queue_packet_buffers){ - if(bm->queue_size==0){ - oggpack_writeclear(bm->queue_packet_buffers); - _ogg_free(bm->queue_packet_buffers); - }else{ - for(i=0;iqueue_size;i++) - oggpack_writeclear(bm->queue_packet_buffers+i); - _ogg_free(bm->queue_packet_buffers); - } - } - if(bm->queue_packets)_ogg_free(bm->queue_packets); - memset(bm,0,sizeof(*bm)); - } + memset(bm,0,sizeof(*bm)); + return; } int vorbis_bitrate_managed(vorbis_block *vb){ vorbis_dsp_state *vd=vb->vd; - backend_lookup_state *b=vd->backend_state; + private_state *b=vd->backend_state; bitrate_manager_state *bm=&b->bms; - if(bm->queue_binned)return(1); + if(bm && bm->managed)return(1); return(0); } -int vorbis_bitrate_maxmarkers(void){ - return 8*BITTRACK_DIVISOR; -} - /* finish taking in the block we just processed */ int vorbis_bitrate_addblock(vorbis_block *vb){ - int i; vorbis_block_internal *vbi=vb->internal; vorbis_dsp_state *vd=vb->vd; - backend_lookup_state *b=vd->backend_state; + private_state *b=vd->backend_state; bitrate_manager_state *bm=&b->bms; vorbis_info *vi=vd->vi; codec_setup_info *ci=vi->codec_setup; bitrate_manager_info *bi=&ci->bi; - int eofflag=vb->eofflag; - int head=bm->queue_head; - int next_head=head+1; - int bins=bm->queue_bins; - int minmax_head,new_minmax_head; - - ogg_uint32_t *head_ptr; - oggpack_buffer temp; - - if(!bm->queue_binned){ - oggpack_buffer temp; + + int choice=rint(bm->avgfloat); + long this_bits=oggpack_bytes(vbi->packetblob[choice])*8; + long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper); + long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper); + int samples=ci->blocksizes[vb->W]>>1; + long desired_fill=bi->reservoir_bits*bi->reservoir_bias; + if(!bm->managed){ /* not a bitrate managed stream, but for API simplicity, we'll - buffer one packet to keep the code path clean */ - - if(bm->queue_head)return(-1); /* one has been submitted without - being claimed */ - bm->queue_head++; - - bm->queue_packets[0].packet=oggpack_get_buffer(&vb->opb); - bm->queue_packets[0].bytes=oggpack_bytes(&vb->opb); - bm->queue_packets[0].b_o_s=0; - bm->queue_packets[0].e_o_s=vb->eofflag; - bm->queue_packets[0].granulepos=vb->granulepos; - bm->queue_packets[0].packetno=vb->sequence; /* for sake of completeness */ - - memcpy(&temp,bm->queue_packet_buffers,sizeof(vb->opb)); - memcpy(bm->queue_packet_buffers,&vb->opb,sizeof(vb->opb)); - memcpy(&vb->opb,&temp,sizeof(vb->opb)); + buffer the packet to keep the code path clean */ + if(bm->vb)return(-1); /* one has been submitted without + being claimed */ + bm->vb=vb; return(0); } - /* add encoded packet to head */ - if(next_head>=bm->queue_size)next_head=0; - head_ptr=bm->queue_binned+bins*head; - - /* is there room to add a block? In proper use of the API, this will - never come up... but guard it anyway */ - if(next_head==bm->avg_tail || next_head==bm->minmax_tail)return(-1); - - /* add the block to the toplevel queue */ - bm->queue_head=next_head; - bm->queue_actual[head]=(vb->W?0x80000000UL:0); - - /* buffer packet fields */ - bm->queue_packets[head].packet=oggpack_get_buffer(&vb->opb); - bm->queue_packets[head].bytes=oggpack_bytes(&vb->opb); - bm->queue_packets[head].b_o_s=0; - bm->queue_packets[head].e_o_s=vb->eofflag; - bm->queue_packets[head].granulepos=vb->granulepos; - bm->queue_packets[head].packetno=vb->sequence; /* for sake of completeness */ - - /* swap packet buffers */ - memcpy(&temp,bm->queue_packet_buffers+head,sizeof(vb->opb)); - memcpy(bm->queue_packet_buffers+head,&vb->opb,sizeof(vb->opb)); - memcpy(&vb->opb,&temp,sizeof(vb->opb)); - - /* save markers */ - memcpy(head_ptr,vbi->packet_markers,sizeof(*head_ptr)*bins); - - if(bm->avg_binacc) - new_minmax_head=minmax_head=bm->avg_center; - else - new_minmax_head=minmax_head=head; - - /* the average tracking queue is updated first; its results (if it's - in use) are taken into account by the min/max limiter (if min/max - is in use) */ - if(bm->avg_binacc){ - long desired_center=bm->avg_centerdesired; - if(eofflag)desired_center=0; - - /* update the avg head */ - for(i=0;iavg_binacc[i]+=LACING_ADJUST(head_ptr[i]); - bm->avg_sampleacc+=ci->blocksizes[vb->W]>>1; - bm->avg_centeracc+=ci->blocksizes[vb->W]>>1; - - /* update the avg tail if needed */ - while(bm->avg_sampleacc>bm->avg_sampledesired){ - int samples= - ci->blocksizes[bm->queue_actual[bm->avg_tail]&0x80000000UL?1:0]>>1; - for(i=0;iqueue_bins;i++) - bm->avg_binacc[i]-=LACING_ADJUST(bm->queue_binned[bins*bm->avg_tail+i]); - bm->avg_sampleacc-=samples; - bm->avg_tail++; - if(bm->avg_tail>=bm->queue_size)bm->avg_tail=0; - } + bm->vb=vb; - /* update the avg center */ - if(bm->avg_centeracc>desired_center){ - /* choose the new average floater */ - double upper=floater_interpolate(bm,vi,bi->queue_avgmax); - double lower=floater_interpolate(bm,vi,bi->queue_avgmin); - double new=bi->avgfloat_initial,slew; - int bin; - - if(upper>0. && upperavgfloat_minimum) - lower=bi->avgfloat_minimum; - if(lower>new)new=lower; - - slew=new-bm->avgfloat; - - if(slewavgfloat_downhyst || slew>bi->avgfloat_uphyst){ - if(slewavgfloat_downslew_max) - new=bm->avgfloat+bi->avgfloat_downslew_max; - if(slew>bi->avgfloat_upslew_max) - new=bm->avgfloat+bi->avgfloat_upslew_max; - - bm->avgfloat=new; - } - - /* apply the average floater to new blocks */ - bin=bm->avgfloat*BITTRACK_DIVISOR; /* truncate on purpose */ - fprintf(stderr,"float:%d ",bin); - while(bm->avg_centeracc>desired_center){ - int samples= - samples=ci->blocksizes[bm->queue_actual[bm->avg_center]& - 0x80000000UL?1:0]>>1; - - bm->queue_actual[bm->avg_center]|=bin; - - bm->avg_centeracc-=samples; - bm->avg_center++; - if(bm->noisetrigger_postpone)bm->noisetrigger_postpone-=samples; - if(bm->avg_center>=bm->queue_size)bm->avg_center=0; + /* look ahead for avg floater */ + if(bm->avg_bitsper>0){ + double slew=0.; + long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); + double slewlimit= 15./bi->slew_damp; + + /* choosing a new floater: + if we're over target, we slew down + if we're under target, we slew up + + choose slew as follows: look through packetblobs of this frame + and set slew as the first in the appropriate direction that + gives us the slew we want. This may mean no slew if delta is + already favorable. + + Then limit slew to slew max */ + + if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ + while(choice>0 && this_bits>avg_target_bits && + bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ + choice--; + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; } - new_minmax_head=bm->avg_center; - - /* track noise bias triggers and noise bias */ - if(bm->avgfloatavgfloat_noise_lowtrigger) - bm->noisetrigger_request+=1.f; - - if(bm->avgfloat>bi->avgfloat_noise_hightrigger) - bm->noisetrigger_request-=1.f; - - if(bm->noisetrigger_postpone<=0){ - if(bm->noisetrigger_request<0.){ - bm->avgnoise-=1.f; - if(bm->noisetrigger_requestavg_sampleacc/2) - bm->avgnoise-=1.f; - bm->noisetrigger_postpone=bm->avg_sampleacc/2; - } - if(bm->noisetrigger_request>0.){ - bm->avgnoise+=1.f; - if(bm->noisetrigger_request>bm->avg_sampleacc/2) - bm->avgnoise+=1.f; - bm->noisetrigger_postpone=bm->avg_sampleacc/2; - } - - /* we generally want the noise bias to drift back to zero */ - bm->noisetrigger_request=0.f; - if(bm->avgnoise>0) - bm->noisetrigger_request= -1.; - if(bm->avgnoise<0) - bm->noisetrigger_request= +1.; - - if(bm->avgnoiseavgfloat_noise_minval) - bm->avgnoise=bi->avgfloat_noise_minval; - if(bm->avgnoise>bi->avgfloat_noise_maxval) - bm->avgnoise=bi->avgfloat_noise_maxval; + }else if(bm->avg_reservoir+(this_bits-avg_target_bits)avg_reservoir+(this_bits-avg_target_bits)packetblob[choice])*8; } - fprintf(stderr,"noise:%f req:%ld trigger:%ld\n",bm->avgnoise, - bm->noisetrigger_request,bm->noisetrigger_postpone); - } - }else{ - /* if we're not using an average tracker, the 'float' is nailed to - the avgfloat_initial value. It needs to be set for the min/max - to deal properly */ - long bin=bi->avgfloat_initial*BITTRACK_DIVISOR; /* truncate on purpose */ - bm->queue_actual[head]|=bin; - new_minmax_head=next_head; - } - - /* update the min/max queues and enforce limits */ - if(bm->minmax_binstack){ - long sampledesired=eofflag?0:bm->minmax_sampledesired; - - /* add to stack recent */ - while(minmax_head!=new_minmax_head){ - int samples=ci->blocksizes[bm->queue_actual[minmax_head]& - 0x80000000UL?1:0]>>1; - - /* the construction here is not parallel to the floater's - stack. - - floater[bin-1] <-> floater supported at bin - ... - floater[0] <-> floater supported at 1 - supported at zero is implicit. - the BINBITS macro performs offsetting - - - bin minmax[bin*2-1] <-> floater supported at bin - ... - 1 minmax[bin] <-> floater supported at 1 - 0 minmax[bin-1] <-> no limit/support (limited to/supported at bin 0, - ie, no effect) - -1 minmax[bin-2] <-> floater limited to bin-1 - ... - -bin+1 minmax[0] <-> floater limited to 1 - limited to zero (val= -bin) is implicit - */ - for(i=0;iminmax_binstack[bm->minmax_stackptr*bins*2+bins+i]+= - LACING_ADJUST( - BINBITS(minmax_head, - (bm->queue_actual[minmax_head]&0x7fffffffUL)>i+1? - (bm->queue_actual[minmax_head]&0x7fffffffUL):i+1)); - - bm->minmax_binstack[bm->minmax_stackptr*bins*2+i]+= - LACING_ADJUST( - BINBITS(minmax_head, - (bm->queue_actual[minmax_head]&0x7fffffffUL)queue_actual[minmax_head]&0x7fffffffUL):i+1)); + + slew=rint(choice-bm->avgfloat)/samples*vi->rate; + if(slew<-slewlimit)slew=-slewlimit; + if(slew>slewlimit)slew=slewlimit; + choice=rint(bm->avgfloat+= slew/vi->rate*samples); + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; + } + + + + /* enforce min(if used) on the current floater (if used) */ + if(bm->min_bitsper>0){ + /* do we need to force the bitrate up? */ + if(this_bitsminmax_reservoir-(min_target_bits-this_bits)<0){ + choice++; + if(choice>=PACKETBLOBS)break; + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; } - - bm->minmax_posstack[bm->minmax_stackptr]=minmax_head; /* not one - past - like - typical */ - bm->minmax_limitstack[bm->minmax_stackptr]=0; - bm->minmax_sampleacc+=samples; - bm->minmax_acctotal+= - LACING_ADJUST( - BINBITS(minmax_head,(bm->queue_actual[minmax_head]&0x7fffffffUL))); - - minmax_head++; - if(minmax_head>=bm->queue_size)minmax_head=0; } + } - /* check limits, enforce changes */ - if(bm->minmax_sampleacc>sampledesired){ - double bitrate=(double)bm->minmax_acctotal/bm->minmax_sampleacc*vi->rate; - int limit=0; - - fprintf(stderr,"prelimit:%dkbps ",(int)bitrate/1000); - if(bitrate>bi->queue_hardmax || bitratequeue_hardmin){ - int newstack; - int stackctr; - long bitsum=limit_sum(bm,0); - bitrate=(double)bitsum/bm->minmax_sampleacc*vi->rate; - - /* we're off rate. Iteratively try out new hard floater - limits until we find one that brings us inside. Here's - where we see the whole point of the limit stacks. */ - if(bitrate>bi->queue_hardmax){ - for(limit=-1;limit>-bins;limit--){ - long bitsum=limit_sum(bm,limit); - bitrate=(double)bitsum/bm->minmax_sampleacc*vi->rate; - if(bitrate<=bi->queue_hardmax)break; - } - }else if(bitratequeue_hardmin){ - for(limit=1;limitminmax_sampleacc*vi->rate; - if(bitrate>=bi->queue_hardmin)break; - } - if(bitrate>bi->queue_hardmax)limit--; - } - - bitsum=limit_sum(bm,limit); - bitrate=(double)bitsum/bm->minmax_sampleacc*vi->rate; - fprintf(stderr,"postlimit:%dkbps ",(int)bitrate/1000); - - /* trace the limit backward, stop when we see a lower limit */ - newstack=bm->minmax_stackptr-1; - while(newstack>=0){ - if(bm->minmax_limitstack[newstack]minmax_stackptr; - while(stackctr>newstack){ - bm->minmax_acctotal-= - LIMITBITS(stackctr,bm->minmax_limitstack[stackctr]); - bm->minmax_acctotal+=LIMITBITS(stackctr,limit); - - if(stackctrminmax_stackptr) - for(i=0;iminmax_binstack[stackctr*bins*2+i]+= - bm->minmax_binstack[(stackctr+1)*bins*2+i]; - - stackctr--; - } - stackctr++; - bm->minmax_posstack[stackctr]=bm->minmax_posstack[bm->minmax_stackptr]; - bm->minmax_limitstack[stackctr]=limit; - fprintf(stderr,"limit:%d\n",limit); - - /* set up new blank stack entry */ - stackctr++; - bm->minmax_stackptr=stackctr; - memset(&bm->minmax_binstack[stackctr*bins*2], - 0, - sizeof(*bm->minmax_binstack)*bins*2); - bm->minmax_limitstack[stackctr]=0; - bm->minmax_posstack[stackctr]=-1; - + /* enforce max (if used) on the current floater (if used) */ + if(bm->max_bitsper>0){ + /* do we need to force the bitrate down? */ + if(this_bits>max_target_bits){ + while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){ + choice--; + if(choice<0)break; + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; } } - - /* remove from tail */ - while(bm->minmax_sampleacc>sampledesired){ - int samples= - ci->blocksizes[bm->queue_actual[bm->minmax_tail]&0x80000000UL?1:0]>>1; - int actual=bm->queue_actual[bm->minmax_tail]&0x7fffffffUL; - - for(i=0;iminmax_binstack[bins+i]-= /* always comes off the stack bottom */ - LACING_ADJUST(BINBITS(bm->minmax_tail,actual>i+1?actual:i+1)); - bm->minmax_binstack[i]-= - LACING_ADJUST(BINBITS(bm->minmax_tail,actualminmax_limitstack[0]>actual) - actual=bm->minmax_limitstack[0]; - if(bins+bm->minmax_limitstack[0]minmax_limitstack[0]; - - bm->minmax_acctotal-=LACING_ADJUST(BINBITS(bm->minmax_tail,actual)); - bm->minmax_sampleacc-=samples; - - /* revise queue_actual to reflect the limit */ - bm->queue_actual[bm->minmax_tail]=actual; - - if(bm->minmax_tail==bm->minmax_posstack[0]){ - /* the stack becomes a FIFO; the first data has fallen off */ - memmove(bm->minmax_binstack,bm->minmax_binstack+bins*2, - sizeof(*bm->minmax_binstack)*bins*2*bm->minmax_stackptr); - memmove(bm->minmax_posstack,bm->minmax_posstack+1, - sizeof(*bm->minmax_posstack)*bm->minmax_stackptr); - memmove(bm->minmax_limitstack,bm->minmax_limitstack+1, - sizeof(*bm->minmax_limitstack)*bm->minmax_stackptr); - bm->minmax_stackptr--; - } + /* Choice of packetblobs now made based on floater, and min/max + requirements. Now boundary check extreme choices */ + + if(choice<0){ + /* choosing a smaller packetblob is insufficient to trim bitrate. + frame will need to be truncated */ + long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8; + bm->choice=choice=0; - bm->minmax_tail++; - if(bm->minmax_tail>=bm->queue_size)bm->minmax_tail=0; + if(oggpack_bytes(vbi->packetblob[choice])>maxsize){ + + oggpack_writetrunc(vbi->packetblob[choice],maxsize*8); + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; } - - - bm->last_to_flush=bm->minmax_tail; }else{ - bm->last_to_flush=bm->avg_center; - } - if(eofflag) - bm->last_to_flush=bm->queue_head; - return(0); -} + long minsize=(min_target_bits-bm->minmax_reservoir+7)/8; + if(choice>=PACKETBLOBS) + choice=PACKETBLOBS-1; -int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){ - backend_lookup_state *b=vd->backend_state; - bitrate_manager_state *bm=&b->bms; + bm->choice=choice; - if(bm->queue_size==0){ - if(bm->queue_head==0)return(0); + /* prop up bitrate according to demand. pad this frame out with zeroes */ + minsize-=oggpack_bytes(vbi->packetblob[choice]); + while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8); + this_bits=oggpack_bytes(vbi->packetblob[choice])*8; - memcpy(op,bm->queue_packets,sizeof(*op)); - bm->queue_head=0; + } - }else{ - long bins=bm->queue_bins; - long bin; - long bytes; + /* now we have the final packet and the final packet size. Update statistics */ + /* min and max reservoir */ + if(bm->min_bitsper>0 || bm->max_bitsper>0){ - if(bm->next_to_flush==bm->last_to_flush)return(0); + if(max_target_bits>0 && this_bits>max_target_bits){ + bm->minmax_reservoir+=(this_bits-max_target_bits); + }else if(min_target_bits>0 && this_bitsminmax_reservoir+=(this_bits-min_target_bits); + }else{ + /* inbetween; we want to take reservoir toward but not past desired_fill */ + if(bm->minmax_reservoir>desired_fill){ + if(max_target_bits>0){ /* logical bulletproofing against initialization state */ + bm->minmax_reservoir+=(this_bits-max_target_bits); + if(bm->minmax_reservoirminmax_reservoir=desired_fill; + }else{ + bm->minmax_reservoir=desired_fill; + } + }else{ + if(min_target_bits>0){ /* logical bulletproofing against initialization state */ + bm->minmax_reservoir+=(this_bits-min_target_bits); + if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill; + }else{ + bm->minmax_reservoir=desired_fill; + } + } + } + } - bin=bm->queue_actual[bm->next_to_flush]&0x7fffffffUL; - bytes=(BINBITS(bm->next_to_flush,bin)+7)/8; - - memcpy(op,bm->queue_packets+bm->next_to_flush,sizeof(*op)); - if(bytesbytes)op->bytes=bytes; + /* avg reservoir */ + if(bm->avg_bitsper>0){ + long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); + bm->avg_reservoir+=this_bits-avg_target_bits; + } - bm->next_to_flush++; - if(bm->next_to_flush>=bm->queue_size)bm->next_to_flush=0; + return(0); +} +int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){ + private_state *b=vd->backend_state; + bitrate_manager_state *bm=&b->bms; + vorbis_block *vb=bm->vb; + int choice=PACKETBLOBS/2; + if(!vb)return 0; + + if(op){ + vorbis_block_internal *vbi=vb->internal; + + if(vorbis_bitrate_managed(vb)) + choice=bm->choice; + + op->packet=oggpack_get_buffer(vbi->packetblob[choice]); + op->bytes=oggpack_bytes(vbi->packetblob[choice]); + op->b_o_s=0; + op->e_o_s=vb->eofflag; + op->granulepos=vb->granulepos; + op->packetno=vb->sequence; /* for sake of completeness */ } + bm->vb=0; return(1); }