summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <xiphmont@xiph.org>2001-11-16 08:17:07 +0000
committerMonty <xiphmont@xiph.org>2001-11-16 08:17:07 +0000
commite12c7a09341cab3512fc58e3a00fa0dd9307961b (patch)
treec83782a94ab7a80dbc98ffc34e865c6973d7e393
parent3442e4f00e69193d2fd2b1af7d92054b78d5a61f (diff)
downloadlibvorbis-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.c112
-rw-r--r--lib/bitrate.c472
-rw-r--r--lib/bitrate.h100
-rw-r--r--lib/block.c31
-rw-r--r--lib/codec_internal.h40
-rw-r--r--lib/mapping0.c128
-rw-r--r--lib/psy.c21
-rw-r--r--lib/psy.h5
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);
+
+
+
}
}
diff --git a/lib/psy.c b/lib/psy.c
index ac97539e..15ee8d88 100644
--- a/lib/psy.c
+++ b/lib/psy.c
@@ -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;
}
diff --git a/lib/psy.h b/lib/psy.h
index 60b62ca2..e286f5bf 100644
--- a/lib/psy.h
+++ b/lib/psy.h
@@ -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,