diff options
author | Monty <xiphmont@xiph.org> | 2001-11-16 08:17:07 +0000 |
---|---|---|
committer | Monty <xiphmont@xiph.org> | 2001-11-16 08:17:07 +0000 |
commit | e12c7a09341cab3512fc58e3a00fa0dd9307961b (patch) | |
tree | c83782a94ab7a80dbc98ffc34e865c6973d7e393 | |
parent | 3442e4f00e69193d2fd2b1af7d92054b78d5a61f (diff) | |
download | libvorbis-git-e12c7a09341cab3512fc58e3a00fa0dd9307961b.tar.gz |
Incremental commit of take-two higher latency but more stable
bitrate management
svn path=/branches/branch_monty_20011009/vorbis/; revision=2383
-rw-r--r-- | lib/analysis.c | 112 | ||||
-rw-r--r-- | lib/bitrate.c | 472 | ||||
-rw-r--r-- | lib/bitrate.h | 100 | ||||
-rw-r--r-- | lib/block.c | 31 | ||||
-rw-r--r-- | lib/codec_internal.h | 40 | ||||
-rw-r--r-- | lib/mapping0.c | 128 | ||||
-rw-r--r-- | lib/psy.c | 21 | ||||
-rw-r--r-- | lib/psy.h | 5 |
8 files changed, 781 insertions, 128 deletions
diff --git a/lib/analysis.c b/lib/analysis.c new file mode 100644 index 00000000..a0bac6f1 --- /dev/null +++ b/lib/analysis.c @@ -0,0 +1,112 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis 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 OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: single-block PCM analysis mode dispatch + last mod: $Id: analysis.c,v 1.46.4.1 2001/11/16 08:17:04 xiphmont Exp $ + + ********************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <ogg/ogg.h> +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "registry.h" +#include "scales.h" +#include "os.h" + +int analysis_noisy=1; + +int vorbis_analysis_packetout(vorbis_block *vb,ogg_packet *op){ + return(vorbis_bitrate_flushpacket(&(vb->bms),op)); +} + +/* decides between modes, dispatches to the appropriate mapping. */ +int vorbis_analysis(vorbis_block *vb){ + vorbis_dsp_state *vd=vb->vd; + backend_lookup_state *b=vd->backend_state; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + int type,ret; + int mode=0; + + vb->glue_bits=0; + vb->time_bits=0; + vb->floor_bits=0; + vb->res_bits=0; + + /* first things first. Make sure encode is ready */ + oggpack_reset(&vb->opb); + /* Encode the packet type */ + oggpack_write(&vb->opb,0,1); + + /* currently lazy. Short block dispatches to 0, long to 1. */ + + if(vb->W &&ci->modes>1)mode=1; + type=ci->map_type[ci->mode_param[mode]->mapping]; + vb->mode=mode; + + /* Encode frame mode, pre,post windowsize, then dispatch */ + oggpack_write(&vb->opb,mode,b->modebits); + if(vb->W){ + oggpack_write(&vb->opb,vb->lW,1); + oggpack_write(&vb->opb,vb->nW,1); + /*fprintf(stderr,"*"); + }else{ + fprintf(stderr,".");*/ + } + + if((ret=_mapping_P[type]->forward(vb,b->mode[mode]))) + return(ret); + + return(vorbis_bitrate_addblock(vb)); +} + +/* there was no great place to put this.... */ +void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB){ + int j; + FILE *of; + char buffer[80]; + + /* if(i==5870){*/ + sprintf(buffer,"%s_%d.m",base,i); + of=fopen(buffer,"w"); + + if(!of)perror("failed to open data dump file"); + + for(j=0;j<n;j++){ + if(dB && v[j]==0) + fprintf(of,"\n\n"); + else{ + if(bark) + fprintf(of,"%g ",toBARK(22050.f*j/n)); + else + fprintf(of,"%g ",(double)j); + + if(dB){ + fprintf(of,"%g\n",todB(v+j)); + }else{ + fprintf(of,"%g\n",v[j]); + } + } + } + fclose(of); + /* } */ +} + +void _analysis_output(char *base,int i,float *v,int n,int bark,int dB){ +#ifdef ANALYSIS + if(analysis_noisy)_analysis_output_always(base,i,v,n,bark,dB); +#endif +} + diff --git a/lib/bitrate.c b/lib/bitrate.c new file mode 100644 index 00000000..2eaa9cfc --- /dev/null +++ b/lib/bitrate.c @@ -0,0 +1,472 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis 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 OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: bitrate tracking and management + last mod: $Id: bitrate.c,v 1.1.2.1 2001/11/16 08:17:04 xiphmont Exp $ + + ********************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <ogg/ogg.h> +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "os.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) + +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; + } + + hibitrate=(double)(bin>=bm->queue_bins?bm->avg_binacc[bm->queue_bins-1]: + bm->avg_binacc[bin])/bm->avg_sampleacc*vi->rate; + while(hibitrate<desired_rate && bin<bm->queue_bins){ + bin++; + if(bin<bm->queue_bins) + hibitrate=(double)bm->avg_binacc[bin]/bm->avg_sampleacc*vi->rate; + } + + /* 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; + } +} + +/* 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; + + 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); +} + +void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){ + /* compute bitrate tracking setup, allocate circular packet size queue */ + { + codec_setup_info *ci=vi->codec_setup; + bitrate_manager_info *bi=ci->bi; + long maxlatency; + + memset(bm,0,sizeof(*bm)); + + 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; + + if(bm->avg_sampledesired<0)bm->avg_sampledesired=0; + if(bm->avg_centerdesired<0)bm->avg_centerdesired=0; + if(bm->minmax_sampledesired<0)bm->minmax_sampledesired=0; + + /* first find the max possible needed queue size */ + maxlatency=max(bm->avg_sampledesired-bm->avg_centerdesired, + bi->queue_minmax_time)+bm->avg_centerdesired; + + if(maxlatency>0){ + long maxpackets=maxlatency/ci->blocksizes[0]+3; + long bins=BITTRACK_DIVISOR*ci->passlimit[ci->coupling_passes-1]; + + bm->queue_size=maxpackets; + bm->queue_bins=bins; + b->queue_binned=_ogg_malloc(maxpackets*bins*sizeof(*b->queue_binned)); + b->queue_actual=_ogg_malloc(maxpackets*sizeof(*b->queue_actual)); + + if((bi->queue_avgmin>0 || bi->queue_avgmax>0) && + bi->queue_avg_time>0){ + + bm->avg_binacc=_ogg_malloc(bins*sizeof(*bm->binacc)); + bm->avgfloat=bi->avgfloat_initial; + + + } + + 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)); + } + } + } +} + +void vorbis_bitrate_clear(bitrate_manager_state *bm){ + 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); + memset(bm,0,sizeof(*bm)); + } +} + +/* makes the accumulation buffer available to the encode process */ +ogg_uint32_t vorbis_bitrate_bufferblock(vorbis_block *vb){ + bitrate_manager_state *bm=&vb->bms; + int next_head=bm->queue_head+1; + if(!bm->queue_binned)return(NULL); + if(next_head>bm->queue_size)next_head==0; + + /* 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(NULL); + return(bm->queue_binned+bm->queue_head*bm->queue_bins); +} + +/* finish taking in the block we just processed */ +int vorbis_bitrate_addblock(vorbis_block *vb){ + int i,j; + bitrate_manager_state *bm=&vb->bms; + vorbis_dsp_state *vd=vb->vd; + backend_lookup_state *b=vd->backend_state; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + int eofflag=vd->eofflag; + int head=bm->queue_head; + int next_head=head+1; + int bins=bm->queue_bins; + int avg_head=head; + int minmax_head,new_minmax_head; + + ogg_uint32_t *head_ptr; + + if(!bm->queue_binned)return(0); + 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; the buffer is already set */ + bm->head=next_head; + bm->queue_actual[head]=(vb->W?0x80000000UL:0); + + if(bm->avg_binacc) + minmax_head=bm->avg_center; + else + 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;i<bins;i++) + bm->avg_binacc[i]+=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=(bm->queue_actual[b->avg_tail]&0x80000000UL? + samples=ci->blocksizes[1]>>1: + samples=ci->blocksizes[0]>>1); + for(i=0;i<bm->queue_bins;i++) + bm->avg_binacc[i]-=bm->queue_binned[bins*bm->queue_tail+i]; + bm->avg_sampleacc-=samples; + bm->avg_tail++; + if(bm->avg_tail>=bm->queue_size)bm->avg_tail=0; + } + + /* update the avg 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. && upper<new)new=upper; + if(lower<bi->avgfloat_minimum) + lower=bi->bitrate_avgfloat_minimum; + if(lower>new)new=lower; + + slew=new-bm->avgfloat; + + if(slew<bi->avgfloat_downhyst || slew>bi->avgfloat_uphyst){ + if(slew<bi->avgfloat_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 */ + while(bm->avg_centeracc>desired_center){ + int samples=(bm->queue_actual[b->avg_tail]&0x80000000UL? + samples=ci->blocksizes[1]>>1: + samples=ci->blocksizes[0]>>1); + + bm->queue_actual[bm->avg_center]|=bin; + + bm->avg_centeracc-=samples; + bm->avg_center++; + if(bm->noisetrigger_postpone)bm->noisetrigger_postpone--; + if(bm->avg_center>=bm->queue_size)bm->avg_center=0; + } + new_minmax_head=bm->avg_center; + + /* track noise bias triggers and noise bias */ + if(bm->avgfloat<bi->avgfloat_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_request<bm->avg_sampleacc/2) + bm->avgnoise-=1.f; + bm->noisetrigger_postpone=bm->avg_sampleacc; + } + 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; + } + + /* 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->avgnoise<bi->avgfloat_noisetrigger_minoff) + bm->avgnoise=bi->avgfloat_noisetrigger_minoff; + if(bm->avgnoise>bi->avgfloat_noisetrigger_maxoff) + bm->avgnoise=bi->avgfloat_noisetrigger_maxoff; + } + } + }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 */ + bin=bi->avgfloat_initial*BITTRACK_DIVISOR; /* truncate on purpose */ + bm->queue_actual[head]|=bin; + new_minmax_head=new_head; + } + + /* update the min/max queues and enforce limits */ + if(bm->minmax_binstack){ + + /* add to stack recent */ + while(minmax_head!=new_minmax_head){ + int samples=(vb->W? + samples=ci->blocksizes[1]>>1: + samples=ci->blocksizes[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;i<bins;i++){ + bm->minmax_binstack[bm->minmax_stackptr*bins*2+bins+i]+= + BINBITS(minmax_head, + (bm->queue_actual[minmax_head]&0x7fffffffUL)>i+1? + (bm->queue_actual[minmax_head]&0x7fffffffUL):i+1); + + bm->minmax_binstack[bm->max_stackptr*bins*2+i]+= + BINBITS(minmax_head, + (bm->queue_actual[minmax_head]&0x7fffffffUL)<i+1? + (bm->queue_actual[minmax_head]&0x7fffffffUL):i+1); + } + + bm->minmax_posstack[bm->max_stackptr]=minmax_head; /* not one past like + typical */ + bm->minmax_limitstack[bm->max_stackptr]=0; + bm->minmax_sampleacc+=samples; + bm->minmax_acctotal+= + BINBITS(minmax_head,(bm->queue_actual[minmax_head]&0x7fffffffUL)); + + minmax_head++; + if(minmax_head>=bm->queue_size)minmax_head=0; + } + + /* remove from tail */ + while(bm->minmax_sampleacc>bm->minmax_sampledesired){ + int samples=(bm->queue_actual[bm->minmax_tail]&0x80000000UL? + samples=ci->blocksizes[1]>>1: + samples=ci->blocksizes[0]>>1); + int actual=bm->queue_actual[bm->minmax_tail]&0x7fffffffUL; + + for(i=0;i<bins;i++){ + bm->min_binstack[bins+i]-= /* always comes off the stack bottom */ + BINBITS(bm->minmax_tail, + (bm->queue_actual[bm->minmax_tail]&0x7fffffffUL)>i+1? + (bm->queue_actual[bm->minmax_tail]&0x7fffffffUL):i+1); + bm->max_binstack[i]-= + BINBITS(bm->minmax_tail, + (bm->queue_actual[bm->minmax_tail]&0x7fffffffUL)<i+1? + (bm->queue_actual[bm->minmax_tail]&0x7fffffffUL):i+1); + } + + if(bm->minmax_tail==bm->minmax_posstack[0]){ + /* the stack becomes a FILO; we've fallen off the end of the + first data */ + 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--; + } + + /* always perform in this order; max overrules min */ + if(bm->minmax_limitstack[0]>actual) + actual=bm->minmax_limitstack[0]; + if(bins+bm->minmax_limitstack[0]<actual) + actual=bins+bm->minmax_limitstack[0]; + + bm->minmax_acctotal-=BINBITS(bm->minmax_tail,actual); + bm->minmax_sampleacc-=samples; + bm->minmax_tail++; + if(bm->minmax_tail>bm->queue_size)bm->minmax_tail=bm->queue_size; + } + + /* check limits, enforce changes */ + if(bm->minmax_binstack){ + double bitrate=(double)bm->minmax_acctotal/bm->minmax_sampleacc*vi->rate; + int limit=0; + if(bitrate>bi->queue_hardmax || bitrate<bi->queue_hardmax){ + int limit=0; + int newstack; + int stcakctr; + /* 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(bitrate<bi->queue_hardmin){ + for(limit=1;limit<bins*2;limit++){ + long bitsum=limit_sum(bm,limit); + bitrate=(double)bitsum/bm->minmax_sampleacc*vi->rate; + if(bitrate>=bi->queue_hardmax)break; + } + } + + /* trace the limit backward, stop when we see a lower limit */ + newstack=bm->minmax_stackptr-1; + while(newstack>=0){ + if(bm->minmax_limitstack[newstack]<limit)break; + newstack--; + } + + /* update bit counter with new limit and replace any stack + limits that have been replaced by our new lower limit */ + stackctr=bm->minmax_stackptr; + while(stackctr>newstack){ + bm->minmax_acctotal-= + LIMITBITS(stackctr,bm->minmax_limitstack[stackctr]); + bm->minmax_acctotal+=LIMITBITS(stackctr,limit); + + if(stackctr<bm->minmax_stackptr) + for(i=0;i<bins*2;i++) + bm->minmax_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; + + /* 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; + + } + } + + bm->last_to_flush=bm->minmax_tail; + }else{ + bm->last_to_flush=bm->avg_center; + } + if(eofflag) + bm->last_to_flush=bm->head; + return(0); +} + +int vorbis_bitrate_flushpacket(bitrate_manager_state *bm, vorbis_packet *op){ + vorbis_dsp_state *vd=vb->vd; + backend_lookup_state *b=vd->backend_state; + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + int eofflag=vd->eofflag; + + if(bm + + +} diff --git a/lib/bitrate.h b/lib/bitrate.h new file mode 100644 index 00000000..b7436d66 --- /dev/null +++ b/lib/bitrate.h @@ -0,0 +1,100 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis 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 OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ******************************************************************** + + function: bitrate tracking and management + last mod: $Id: bitrate.h,v 1.1.2.1 2001/11/16 08:17:06 xiphmont Exp $ + + ********************************************************************/ + +#ifndef _V_BITRATE_H_ +#define _V_BITRATE_H_ + +#include "vorbis/codec.h" +#include "codec_internal.h" +#include "os.h" + +/* encode side bitrate tracking */ +#define BITTRACK_DIVISOR 16 +typedef struct bitrate_manager_state { + ogg_uint32_t *queue_binned; + ogg_uint32_t *queue_actual; + int queue_size; + + int queue_head; + int queue_bins; + + long *avg_binacc; + int avg_center; + int avg_tail; + ogg_uint32_t avg_centeracc; + ogg_uint32_t avg_sampleacc; + ogg_uint32_t avg_sampledesired; + ogg_uint32_t avg_centerdesired; + + long *minmax_binstack; + long *minmax_posstack; + long *minmax_limitstack; + long minmax_stackptr; + + long minmax_acctotal; + int minmax_tail; + ogg_uint32_t minmax_sampleacc; + ogg_uint32_t minmax_sampledesired; + + int next_to_flush; + int last_to_flush; + + double avgfloat; + double avgnoise; + long noisetrigger_postpone; + long noisetrigger_request; + + /* unfortunately, we need to hold queued packet data somewhere */ + unsigned char *packetdoublebuffer[2]; + unsigned char doublebufferhead[2]; + unsigned char doublebuffertail[2]; + oggpack_buffer *queue_packets; + +} bitrate_manager_state; + +typedef struct bitrate_manager_info{ + /* detailed bitrate management setup */ + double absolute_min_short; + double absolute_min_long; + double absolute_max_short; + double absolute_max_long; + + double queue_avg_time; + double queue_minmax_time; + double queue_hardmin; + double queue_hardmax; + double queue_avgmin; + double queue_avgmax; + + double avgfloat_initial; /* set by mode */ + double avgfloat_minimum; /* set by mode */ + double avgfloat_downslew_max; + double avgfloat_upslew_max; + double avgfloat_downhyst; + double avgfloat_uphyst; + double avgfloat_noise_lowtrigger; + double avgfloat_noise_hightrigger; + double avgfloat_noise_minval; + double avgfloat_noise_maxval; +} bitrate_manager_info; + +extern void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bs); +extern void vorbis_bitrate_clear(bitrate_manager_state *bs); +extern int vorbis_bitrate_addblock(vorbis_block *vb); +extern int vorbis_bitrate_flushpacket(vorbis_block *vb, vorbis_packet *op); + +#endif diff --git a/lib/block.c b/lib/block.c index f437eec8..1e1d0767 100644 --- a/lib/block.c +++ b/lib/block.c @@ -11,7 +11,7 @@ ******************************************************************** function: PCM data vector blocking, windowing and dis/reassembly - last mod: $Id: block.c,v 1.50.2.4 2001/10/20 03:00:09 xiphmont Exp $ + last mod: $Id: block.c,v 1.50.2.5 2001/11/16 08:17:05 xiphmont Exp $ Handle windowing, overlap-add, etc of the PCM vectors. This is made more amusing by Vorbis' current two allowed block sizes. @@ -26,14 +26,10 @@ #include "codec_internal.h" #include "window.h" -#include "envelope.h" #include "mdct.h" #include "lpc.h" #include "registry.h" -#include "codebook.h" #include "misc.h" -#include "os.h" -#include "psy.h" static int ilog2(unsigned int v){ int ret=0; @@ -268,25 +264,7 @@ int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){ b->ve=_ogg_calloc(1,sizeof(*b->ve)); _ve_envelope_init(b->ve,vi); - /* compute bitrate tracking setup, allocate circular packet size queue */ - { - codec_setup_info *ci=vi->codec_setup; - /* first find the max possible needed queue size */ - long maxpackets=(ci->bitrate_queue_time*vi->rate+(ci->blocksizes[0]-1))/ci->blocksizes[0]+1; - long bins=BITTRACK_DIVISOR*ci->passlimit[ci->coupling_passes-1]; - if(ci->bitrate_queue_avgmin<=0. && - ci->bitrate_queue_avgmax<=0.)bins=0; - - b->bitrate_queue_size=maxpackets; - b->bitrate_bins=bins; - b->bitrate_queue_actual=_ogg_malloc(maxpackets*sizeof(*b->bitrate_queue_actual)); - if(bins){ - b->bitrate_queue_binned=_ogg_malloc(maxpackets*bins* - sizeof(*b->bitrate_queue_binned)); - b->bitrate_queue_binacc=_ogg_malloc(bins*sizeof(*b->bitrate_queue_binacc)); - } - b->bitrate_avgfloat=ci->bitrate_avgfloat_initial; - } + vorbis_bitrate_init(vi,&b->bms); return(0); } @@ -328,10 +306,7 @@ void vorbis_dsp_clear(vorbis_dsp_state *v){ _ogg_free(b->transform[1]); } if(b->psy_g_look)_vp_global_free(b->psy_g_look); - if(b->bitrate_queue_actual)_ogg_free(b->bitrate_queue_actual); - if(b->bitrate_queue_binned)_ogg_free(b->bitrate_queue_binned); - if(b->bitrate_queue_binacc)_ogg_free(b->bitrate_queue_binacc); - + vorbis_bitrate_clear(&b->bms); } if(v->pcm){ diff --git a/lib/codec_internal.h b/lib/codec_internal.h index 837d128b..6b692f73 100644 --- a/lib/codec_internal.h +++ b/lib/codec_internal.h @@ -10,7 +10,7 @@ ******************************************************************** function: libvorbis codec headers - last mod: $Id: codec_internal.h,v 1.9.4.4 2001/10/20 03:00:09 xiphmont Exp $ + last mod: $Id: codec_internal.h,v 1.9.4.5 2001/11/16 08:17:06 xiphmont Exp $ ********************************************************************/ @@ -45,8 +45,8 @@ typedef void vorbis_info_residue; typedef void vorbis_info_mapping; #include "psy.h" +#inclide "bitrate.h" -#define BITTRACK_DIVISOR 16 typedef struct backend_lookup_state { /* local lookup storage */ envelope_lookup *ve; /* envelope lookup */ @@ -67,20 +67,7 @@ typedef struct backend_lookup_state { unsigned char *header1; unsigned char *header2; - /* encode side bitrate tracking */ - ogg_uint32_t *bitrate_queue_actual; - ogg_uint32_t *bitrate_queue_binned; - int bitrate_queue_size; - int bitrate_queue_head; - int bitrate_bins; - - /* 0, -1, -4, -16, -n/16, -n/8, -n/4, -n/2 */ - long bitrate_queue_bitacc[8]; - long bitrate_queue_sampleacc[8]; - long bitrate_queue_tail[8]; - long *bitrate_queue_binacc; - - double bitrate_avgfloat; + bitrate_manager_state bms; } backend_lookup_state; @@ -123,26 +110,7 @@ typedef struct codec_setup_info { vorbis_info_psy *psy_param[64]; /* encode only */ vorbis_info_psy_global *psy_g_param; - - /* detailed bitrate management setup */ - double bitrate_absolute_min_short; - double bitrate_absolute_min_long; - double bitrate_absolute_max_short; - double bitrate_absolute_max_long; - - double bitrate_queue_time; - double bitrate_queue_hardmin; - double bitrate_queue_hardmax; - double bitrate_queue_avgmin; - double bitrate_queue_avgmax; - - double bitrate_avgfloat_initial; /* set by mode */ - double bitrate_avgfloat_minimum; /* set by mode */ - double bitrate_avgfloat_downslew_max; - double bitrate_avgfloat_upslew_max; - double bitrate_avgfloat_downhyst; - double bitrate_avgfloat_uphyst; - + bitrate_manager_info *bi; int passlimit[32]; /* iteration limit per couple/quant pass */ int coupling_passes; diff --git a/lib/mapping0.c b/lib/mapping0.c index 8d69bdca..dd0f9394 100644 --- a/lib/mapping0.c +++ b/lib/mapping0.c @@ -11,7 +11,7 @@ ******************************************************************** function: channel mapping 0 implementation - last mod: $Id: mapping0.c,v 1.37.2.6 2001/10/22 09:09:29 xiphmont Exp $ + last mod: $Id: mapping0.c,v 1.37.2.7 2001/11/16 08:17:05 xiphmont Exp $ ********************************************************************/ @@ -23,7 +23,6 @@ #include "vorbis/codec.h" #include "codec_internal.h" #include "codebook.h" -#include "bitbuffer.h" #include "registry.h" #include "psy.h" #include "misc.h" @@ -282,39 +281,6 @@ static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb) #include "psy.h" #include "scales.h" -static double floater_interpolate(backend_lookup_state *b,vorbis_info *vi, - double desired_rate){ - int bin=b->bitrate_avgfloat*BITTRACK_DIVISOR-1.; - double lobitrate; - double hibitrate; - - if(desired_rate<=0.)return(0.); - - lobitrate=(double)(bin==0?0.: - b->bitrate_queue_binacc[bin-1])/b->bitrate_queue_sampleacc[0]*vi->rate; - while(lobitrate>desired_rate && bin>0){ - bin--; - lobitrate=(double)(bin==0?0.: - b->bitrate_queue_binacc[bin-1])/b->bitrate_queue_sampleacc[0]*vi->rate; - } - - hibitrate=(bin>=b->bitrate_bins?b->bitrate_queue_binacc[b->bitrate_bins-1]: - (double)b->bitrate_queue_binacc[bin])/b->bitrate_queue_sampleacc[0]*vi->rate; - while(hibitrate<desired_rate && bin<b->bitrate_bins){ - bin++; - if(bin<b->bitrate_bins) - hibitrate=(double)b->bitrate_queue_binacc[bin]/b->bitrate_queue_sampleacc[0]*vi->rate; - } - - /* interpolate */ - if(bin==b->bitrate_bins){ - return bin/(double)BITTRACK_DIVISOR; - }else{ - double delta=(desired_rate-lobitrate)/(hibitrate-lobitrate); - return (bin+delta)/(double)BITTRACK_DIVISOR; - } -} - /* no time mapping implementation for now */ static long seq=0; static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ @@ -425,7 +391,8 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ logmask, global_ampmax, local_ampmax[i], - ci->blocksizes[vb->lW]/2); + ci->blocksizes[vb->lW]/2, + b->bitrate_avgnoise); _analysis_output("mask",seq+i,logmask,n/2,1,0); /* perform floor encoding */ @@ -577,12 +544,16 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ { long maxbits_absolute= (vb->W? - ci->bitrate_absolute_max_long/vi->rate*ci->blocksizes[1]/2: - ci->bitrate_absolute_max_short/vi->rate*ci->blocksizes[0]/2); + (ci->bitrate_absolute_max_long>0? + ci->bitrate_absolute_max_long/vi->rate*ci->blocksizes[1]/2:-1): + (ci->bitrate_absolute_max_short>0? + ci->bitrate_absolute_max_short/vi->rate*ci->blocksizes[0]/2:-1)); long minbits_absolute= (vb->W? - ci->bitrate_absolute_min_long/vi->rate*ci->blocksizes[1]/2: - ci->bitrate_absolute_min_short/vi->rate*ci->blocksizes[0]/2); + (ci->bitrate_absolute_min_long>0? + ci->bitrate_absolute_min_long/vi->rate*ci->blocksizes[1]/2:-1): + (ci->bitrate_absolute_min_short>0? + ci->bitrate_absolute_min_short/vi->rate*ci->blocksizes[0]/2:-1)); long minbits_period=ci->bitrate_queue_hardmin/vi->rate* (b->bitrate_queue_sampleacc[0]+ci->blocksizes[vb->W]/2)- @@ -592,6 +563,9 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ b->bitrate_queue_sampleacc[0]); long maxbits_period=-1; + maxbits=-1; + minbits=-1; + /* pessimistic checkahead */ for(i=0;i<8;i++){ long ahead_samples=period_samples-b->bitrate_queue_sampleacc[i]; @@ -599,7 +573,7 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ long maxbits_local=ci->bitrate_queue_hardmax/vi->rate* (period_samples+ci->blocksizes[vb->W]/2)- b->bitrate_queue_bitacc[i]- - ci->bitrate_queue_hardmin/vi->rate*ahead_samples; + ci->bitrate_queue_hardmax/vi->rate*ahead_samples; if(maxbits_period==-1 || maxbits_local<maxbits_period) maxbits_period=maxbits_local; @@ -608,18 +582,19 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ } - if(maxbits_absolute){ - if(ci->bitrate_queue_hardmax>0.){ + fprintf(stderr,"maxbits_a %ld maxbit_period %ld\n",maxbits_absolute,maxbits_period); + + if(maxbits_absolute>=0.){ + if(maxbits_period>=0.){ maxbits=min(maxbits_period,maxbits_absolute); }else{ maxbits=maxbits_absolute; } }else - maxbits=maxbits_period; + if(maxbits_period>=0)maxbits=maxbits_period; minbits=max(minbits_period,minbits_absolute); - if(maxbits<0)maxbits=0; - if(maxbits)minbits=min(minbits,maxbits); + if(maxbits>=0)minbits=min(minbits,maxbits); } /* actual encoding loop; if we have a desired stopping point, pack @@ -663,7 +638,7 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ long current_bytes=oggpack_bits(&vb->opb)/8; - if(maxbits && current_bytes>maxbits/8){ + if(maxbits>=0 && current_bytes>maxbits/8){ /* maxbits trumps all... */ stoppos=maxbits/8; stopflag=1; @@ -715,8 +690,8 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ /* truncate the packet according to stoppos */ if(!stoppos)stoppos=oggpack_bytes(&vb->opb); - if(minbits && stoppos*8<minbits)stoppos=(minbits+7)/8; - if(maxbits && stoppos*8>maxbits)stoppos=maxbits/8; + if(minbits>=0 && stoppos*8<minbits)stoppos=(minbits+7)/8; + if(maxbits>=0 && stoppos*8>maxbits)stoppos=maxbits/8; if(stoppos>oggpack_bytes(&vb->opb))stoppos=oggpack_bytes(&vb->opb); vb->opb.endbyte=stoppos; vb->opb.endbit=0; @@ -772,6 +747,9 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ for(j=0;j<b->bitrate_bins;j++) b->bitrate_queue_binacc[j]-= b->bitrate_queue_binned[b->bitrate_queue_tail[0]*b->bitrate_bins+j]; + + /* watch the running noise offset trigger */ + if(b->bitrate_noisetrigger_postpone)--b->bitrate_noisetrigger_postpone; } b->bitrate_queue_tail[i]++; @@ -803,6 +781,7 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ b->bitrate_queue_head++; if(b->bitrate_queue_head>=b->bitrate_queue_size)b->bitrate_queue_head=0; + } /* adjust the floater to offset bitrate above/below desired average */ @@ -812,14 +791,13 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ if(b->bitrate_bins>0 && (b->bitrate_queue_sampleacc[0]>ci->bitrate_queue_time*vi->rate/8 || - b->bitrate_queue_sampleacc[0]>8192)){ + b->bitrate_queue_sampleacc[0]>8192 || b->bitrate_queue_head>16)){ + double upper=floater_interpolate(b,vi,ci->bitrate_queue_avgmax); double lower=floater_interpolate(b,vi,ci->bitrate_queue_avgmin); double new=ci->bitrate_avgfloat_initial; double slew; - fprintf(stderr,"\tupper:%g :: lower:%g\n",upper,lower); - if(upper>0. && upper<new)new=upper; if(lower<ci->bitrate_avgfloat_minimum) lower=ci->bitrate_avgfloat_minimum; @@ -835,6 +813,52 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ b->bitrate_avgfloat=new; } + + { + long queueusage=b->bitrate_queue_head; + if(b->bitrate_queue_tail[0]>b->bitrate_queue_head) + queueusage+=b->bitrate_queue_size; + queueusage-=b->bitrate_queue_tail[0]; + + if(b->bitrate_avgfloat<ci->bitrate_avgfloat_noisetrigger_low) + b->bitrate_noisetrigger_request+=1.f; + + if(b->bitrate_avgfloat>ci->bitrate_avgfloat_noisetrigger_high) + b->bitrate_noisetrigger_request-=1.f; + + if(b->bitrate_noisetrigger_postpone==0){ + if(b->bitrate_noisetrigger_request<0.){ + b->bitrate_avgnoise-=1.f; + if(b->bitrate_noisetrigger_request<10.) + b->bitrate_avgnoise-=1.f; + b->bitrate_noisetrigger_postpone=queueusage; + } + if(b->bitrate_noisetrigger_request>0.){ + b->bitrate_avgnoise+=1.f; + if(b->bitrate_noisetrigger_request>10.) + b->bitrate_avgnoise+=1.f; + b->bitrate_noisetrigger_postpone=queueusage; + } + + b->bitrate_noisetrigger_request=0.f; + if(b->bitrate_avgnoise>0) + b->bitrate_noisetrigger_request= -1.; + if(b->bitrate_avgnoise<0) + b->bitrate_noisetrigger_request= +1.; + + if(b->bitrate_avgnoise<ci->bitrate_avgfloat_noisetrigger_minoff) + b->bitrate_avgnoise=ci->bitrate_avgfloat_noisetrigger_minoff; + if(b->bitrate_avgnoise>ci->bitrate_avgfloat_noisetrigger_maxoff) + b->bitrate_avgnoise=ci->bitrate_avgfloat_noisetrigger_maxoff; + } + } + + fprintf(stderr,"\tupper:%g :: lower:%g (noise offset=%g, pending=%d, trigger=%d)\n", + upper,lower,b->bitrate_avgnoise,b->bitrate_noisetrigger_request, + b->bitrate_noisetrigger_postpone); + + + } } @@ -11,7 +11,7 @@ ******************************************************************** function: psychoacoustics not including preecho - last mod: $Id: psy.c,v 1.56.2.3 2001/10/20 01:03:59 xiphmont Exp $ + last mod: $Id: psy.c,v 1.56.2.4 2001/11/16 08:17:05 xiphmont Exp $ ********************************************************************/ @@ -815,14 +815,15 @@ void _vp_remove_floor(vorbis_look_psy *p, void _vp_compute_mask(vorbis_look_psy *p, - vorbis_look_psy_global *g, - int channel, - float *logfft, - float *logmdct, - float *logmask, - float global_specmax, - float local_specmax, - int lastsize){ + vorbis_look_psy_global *g, + int channel, + float *logfft, + float *logmdct, + float *logmask, + float global_specmax, + float local_specmax, + int lastsize, + float bitrate_noise_offset){ int i,n=p->n; static int seq=0; @@ -849,7 +850,7 @@ void _vp_compute_mask(vorbis_look_psy *p, for(i=0;i<n;i++){ int dB=logmask[i]+.5; if(dB>=NOISE_COMPAND_LEVELS)dB=NOISE_COMPAND_LEVELS-1; - logmask[i]= work[i]+p->vi->noisecompand[dB]+p->noiseoffset[i]; + logmask[i]= work[i]+p->vi->noisecompand[dB]+p->noiseoffset[i]+bitrate_noise_offset; if(logmask[i]>p->vi->noisemaxsupp)logmask[i]=p->vi->noisemaxsupp; } @@ -11,7 +11,7 @@ ******************************************************************** function: random psychoacoustics (not including preecho) - last mod: $Id: psy.h,v 1.24.2.3 2001/10/20 01:03:59 xiphmont Exp $ + last mod: $Id: psy.h,v 1.24.2.4 2001/11/16 08:17:07 xiphmont Exp $ ********************************************************************/ @@ -159,7 +159,8 @@ extern void _vp_compute_mask(vorbis_look_psy *p, float *mask, float global_specmax, float local_specmax, - int lastsize); + int lastsize, + float bitrate_noise_offset); extern void _vp_quantize_couple(vorbis_look_psy *p, vorbis_info_mapping0 *vi, |