summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <xiphmont@xiph.org>2007-06-21 04:59:44 +0000
committerMonty <xiphmont@xiph.org>2007-06-21 04:59:44 +0000
commit90d6b0678e77cd237183c0183c4837a7915e66e9 (patch)
tree28f8afbf933b2485bd281a5d1dd0fc66017eab92
parent9b9440d059b12a72122d851cd7c89e05e188b7ba (diff)
downloadtremor-90d6b0678e77cd237183c0183c4837a7915e66e9.tar.gz
Add proper guarding to cases where declared floor/residue decode size
is *larger* than the current blocksize. Handle according to spec. (nobyte branch) re-add dsp.c that somehow got dropped out of versioning history at some point. git-svn-id: https://svn.xiph.org/branches/lowmem-no-byte/Tremor@13158 0101bb08-14d6-0310-b084-bc0e0c8e3800
-rw-r--r--dsp.c298
-rw-r--r--floor1.c10
-rw-r--r--res012.c206
3 files changed, 414 insertions, 100 deletions
diff --git a/dsp.c b/dsp.c
new file mode 100644
index 0000000..882b685
--- /dev/null
+++ b/dsp.c
@@ -0,0 +1,298 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis 'TREMOR' 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 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
+ * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: PCM data vector blocking, windowing and dis/reassembly
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include "ogg.h"
+#include "mdct.h"
+#include "ivorbiscodec.h"
+#include "codec_internal.h"
+#include "misc.h"
+#include "window_lookup.h"
+
+int vorbis_dsp_restart(vorbis_dsp_state *v){
+ if(!v)return -1;
+ {
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci;
+
+ if(!vi)return -1;
+ ci=vi->codec_setup;
+ if(!ci)return -1;
+
+ v->out_end=-1;
+ v->out_begin=-1;
+
+ v->granulepos=-1;
+ v->sequence=-1;
+ v->sample_count=-1;
+ }
+ return 0;
+}
+
+vorbis_dsp_state *vorbis_dsp_create(vorbis_info *vi){
+ int i;
+
+ vorbis_dsp_state *v=_ogg_calloc(1,sizeof(*v));
+ codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
+
+ v->vi=vi;
+
+ v->work=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->work));
+ v->mdctright=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->mdctright));
+ for(i=0;i<vi->channels;i++){
+ v->work[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>1)*
+ sizeof(*v->work[i]));
+ v->mdctright[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>2)*
+ sizeof(*v->mdctright[i]));
+ }
+
+ v->lW=0; /* previous window size */
+ v->W=0; /* current window size */
+
+ vorbis_dsp_restart(v);
+ return v;
+}
+
+void vorbis_dsp_destroy(vorbis_dsp_state *v){
+ int i;
+ if(v){
+ vorbis_info *vi=v->vi;
+
+ if(v->work){
+ for(i=0;i<vi->channels;i++)
+ if(v->work[i])_ogg_free(v->work[i]);
+ _ogg_free(v->work);
+ }
+ if(v->mdctright){
+ for(i=0;i<vi->channels;i++)
+ if(v->mdctright[i])_ogg_free(v->mdctright[i]);
+ _ogg_free(v->mdctright);
+ }
+
+ _ogg_free(v);
+ }
+}
+
+static LOOKUP_T *_vorbis_window(int left){
+ switch(left){
+ case 32:
+ return vwin64;
+ case 64:
+ return vwin128;
+ case 128:
+ return vwin256;
+ case 256:
+ return vwin512;
+ case 512:
+ return vwin1024;
+ case 1024:
+ return vwin2048;
+ case 2048:
+ return vwin4096;
+#ifndef LIMIT_TO_64kHz
+ case 4096:
+ return vwin8192;
+#endif
+ default:
+ return(0);
+ }
+}
+
+/* pcm==0 indicates we just want the pending samples, no more */
+int vorbis_dsp_pcmout(vorbis_dsp_state *v,ogg_int16_t *pcm,int samples){
+ vorbis_info *vi=v->vi;
+ codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
+ if(v->out_begin>-1 && v->out_begin<v->out_end){
+ int n=v->out_end-v->out_begin;
+ if(pcm){
+ int i;
+ if(n>samples)n=samples;
+ for(i=0;i<vi->channels;i++)
+ mdct_unroll_lap(ci->blocksizes[0],ci->blocksizes[1],
+ v->lW,v->W,v->work[i],v->mdctright[i],
+ _vorbis_window(ci->blocksizes[0]>>1),
+ _vorbis_window(ci->blocksizes[1]>>1),
+ pcm+i,vi->channels,
+ v->out_begin,v->out_begin+n);
+ }
+ return(n);
+ }
+ return(0);
+}
+
+int vorbis_dsp_read(vorbis_dsp_state *v,int s){
+ if(s && v->out_begin+s>v->out_end)return(OV_EINVAL);
+ v->out_begin+=s;
+ return(0);
+}
+
+long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
+ codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
+ oggpack_buffer opb;
+ int mode;
+ int modebits=0;
+ int v=ci->modes;
+
+ oggpack_readinit(&opb,op->packet);
+
+ /* Check the packet type */
+ if(oggpack_read(&opb,1)!=0){
+ /* Oops. This is not an audio data packet */
+ return(OV_ENOTAUDIO);
+ }
+
+ while(v>1){
+ modebits++;
+ v>>=1;
+ }
+
+ /* read our mode and pre/post windowsize */
+ mode=oggpack_read(&opb,modebits);
+ if(mode==-1)return(OV_EBADPACKET);
+ return(ci->blocksizes[ci->mode_param[mode].blockflag]);
+}
+
+
+static int ilog(ogg_uint32_t v){
+ int ret=0;
+ if(v)--v;
+ while(v){
+ ret++;
+ v>>=1;
+ }
+ return(ret);
+}
+
+int vorbis_dsp_synthesis(vorbis_dsp_state *vd,ogg_packet *op,int decodep){
+ vorbis_info *vi=vd->vi;
+ codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
+ int mode,i;
+
+ oggpack_readinit(&vd->opb,op->packet);
+
+ /* Check the packet type */
+ if(oggpack_read(&vd->opb,1)!=0){
+ /* Oops. This is not an audio data packet */
+ return OV_ENOTAUDIO ;
+ }
+
+ /* read our mode and pre/post windowsize */
+ mode=oggpack_read(&vd->opb,ilog(ci->modes));
+ if(mode==-1 || mode>=ci->modes) return OV_EBADPACKET;
+
+ /* shift information we still need from last window */
+ vd->lW=vd->W;
+ vd->W=ci->mode_param[mode].blockflag;
+ for(i=0;i<vi->channels;i++)
+ mdct_shift_right(ci->blocksizes[vd->lW],vd->work[i],vd->mdctright[i]);
+
+ if(vd->W){
+ int temp;
+ oggpack_read(&vd->opb,1);
+ temp=oggpack_read(&vd->opb,1);
+ if(temp==-1) return OV_EBADPACKET;
+ }
+
+ /* packet decode and portions of synthesis that rely on only this block */
+ if(decodep){
+ mapping_inverse(vd,ci->map_param+ci->mode_param[mode].mapping);
+
+ if(vd->out_begin==-1){
+ vd->out_begin=0;
+ vd->out_end=0;
+ }else{
+ vd->out_begin=0;
+ vd->out_end=ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
+ }
+ }
+
+ /* track the frame number... This is for convenience, but also
+ making sure our last packet doesn't end with added padding.
+
+ This is not foolproof! It will be confused if we begin
+ decoding at the last page after a seek or hole. In that case,
+ we don't have a starting point to judge where the last frame
+ is. For this reason, vorbisfile will always try to make sure
+ it reads the last two marked pages in proper sequence */
+
+ /* if we're out of sequence, dump granpos tracking until we sync back up */
+ if(vd->sequence==-1 || vd->sequence+1 != op->packetno-3){
+ /* out of sequence; lose count */
+ vd->granulepos=-1;
+ vd->sample_count=-1;
+ }
+
+ vd->sequence=op->packetno;
+ vd->sequence=vd->sequence-3;
+
+ if(vd->sample_count==-1){
+ vd->sample_count=0;
+ }else{
+ vd->sample_count+=
+ ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
+ }
+
+ if(vd->granulepos==-1){
+ if(op->granulepos!=-1){ /* only set if we have a
+ position to set to */
+
+ vd->granulepos=op->granulepos;
+
+ /* is this a short page? */
+ if(vd->sample_count>vd->granulepos){
+ /* corner case; if this is both the first and last audio page,
+ then spec says the end is cut, not beginning */
+ if(op->e_o_s){
+ /* trim the end */
+ /* no preceeding granulepos; assume we started at zero (we'd
+ have to in a short single-page stream) */
+ /* granulepos could be -1 due to a seek, but that would result
+ in a long coun t, not short count */
+
+ vd->out_end-=vd->sample_count-vd->granulepos;
+ }else{
+ /* trim the beginning */
+ vd->out_begin+=vd->sample_count-vd->granulepos;
+ if(vd->out_begin>vd->out_end)
+ vd->out_begin=vd->out_end;
+ }
+
+ }
+
+ }
+ }else{
+ vd->granulepos+=
+ ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
+ if(op->granulepos!=-1 && vd->granulepos!=op->granulepos){
+
+ if(vd->granulepos>op->granulepos){
+ long extra=vd->granulepos-op->granulepos;
+
+ if(extra)
+ if(op->e_o_s){
+ /* partial last frame. Strip the extra samples off */
+ vd->out_end-=extra;
+ } /* else {Shouldn't happen *unless* the bitstream is out of
+ spec. Either way, believe the bitstream } */
+ } /* else {Shouldn't happen *unless* the bitstream is out of
+ spec. Either way, believe the bitstream } */
+ vd->granulepos=op->granulepos;
+ }
+ }
+
+ return(0);
+}
diff --git a/floor1.c b/floor1.c
index 65959de..384081c 100644
--- a/floor1.c
+++ b/floor1.c
@@ -171,7 +171,7 @@ static int render_point(int x0,int x1,int y0,int y1,int x){
}
}
-static void render_line(int x0,int x1,int y0,int y1,ogg_int32_t *d){
+static void render_line(int n, int x0,int x1,int y0,int y1,ogg_int32_t *d){
int dy=y1-y0;
int adx=x1-x0;
int ady=abs(dy);
@@ -181,11 +181,13 @@ static void render_line(int x0,int x1,int y0,int y1,ogg_int32_t *d){
int y=y0;
int err=0;
+ if(n>x1)n=x1;
ady-=abs(base*adx);
- d[x]= MULT31_SHIFT15(d[x],FLOOR_fromdB_LOOKUP[y]);
+ if(x<n)
+ d[x]= MULT31_SHIFT15(d[x],FLOOR_fromdB_LOOKUP[y]);
- while(++x<x1){
+ while(++x<n){
err=err+ady;
if(err>=adx){
err-=adx;
@@ -311,7 +313,7 @@ int floor1_inverse2(vorbis_dsp_state *vd,vorbis_info_floor *in,
hy*=info->mult;
hx=info->postlist[current];
- render_line(lx,hx,ly,hy,out);
+ render_line(n,lx,hx,ly,hy,out);
lx=hx;
ly=hy;
diff --git a/res012.c b/res012.c
index 73a904e..366f513 100644
--- a/res012.c
+++ b/res012.c
@@ -96,121 +96,135 @@ int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info,
codebook *phrasebook=ci->book_param+info->groupbook;
int samples_per_partition=info->grouping;
int partitions_per_word=phrasebook->dim;
- int n=info->end-info->begin;
- int partvals=n/samples_per_partition;
- int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
+ int pcmend=ci->blocksizes[vd->W];
if(info->type<2){
- for(i=0;i<ch;i++)
- if(nonzero[i])
- in[used++]=in[i];
- ch=used;
-
- if(used){
+ int max=pcmend>>1;
+ int end=(info->end<max?info->end:max);
+ int n=end-info->begin;
+
+ if(n>0){
+ int partvals=n/samples_per_partition;
+ int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
- char **partword=(char **)alloca(ch*sizeof(*partword));
- for(j=0;j<ch;j++)
- partword[j]=(char *)alloca(partwords*partitions_per_word*
- sizeof(*partword[j]));
-
- for(s=0;s<info->stages;s++){
+ for(i=0;i<ch;i++)
+ if(nonzero[i])
+ in[used++]=in[i];
+ ch=used;
+
+ if(used){
+
+ char **partword=(char **)alloca(ch*sizeof(*partword));
+ for(j=0;j<ch;j++)
+ partword[j]=(char *)alloca(partwords*partitions_per_word*
+ sizeof(*partword[j]));
+ for(s=0;s<info->stages;s++){
+
+ for(i=0;i<partvals;){
+ if(s==0){
+ /* fetch the partition word for each channel */
+
+ partword[0][i+partitions_per_word-1]=1;
+ for(k=partitions_per_word-2;k>=0;k--)
+ partword[0][i+k]=partword[0][i+k+1]*info->partitions;
+
+ for(j=1;j<ch;j++)
+ for(k=partitions_per_word-1;k>=0;k--)
+ partword[j][i+k]=partword[j-1][i+k];
+
+ for(j=0;j<ch;j++){
+ int temp=vorbis_book_decode(phrasebook,&vd->opb);
+ if(oggpack_eop(&vd->opb))goto eopbreak;
+
+ /* this can be done quickly in assembly due to the quotient
+ always being at most six bits */
+ for(k=0;k<partitions_per_word;k++){
+ ogg_uint32_t div=partword[j][i+k];
+ partword[j][i+k]=temp/div;
+ temp-=partword[j][i+k]*div;
+ }
+
+ }
+ }
+
+ /* now we decode residual values for the partitions */
+ for(k=0;k<partitions_per_word && i<partvals;k++,i++)
+ for(j=0;j<ch;j++){
+ long offset=info->begin+i*samples_per_partition;
+ if(info->stagemasks[partword[j][i]]&(1<<s)){
+ codebook *stagebook=ci->book_param+
+ info->stagebooks[(partword[j][i]<<3)+s];
+ if(info->type){
+ if(vorbis_book_decodev_add(stagebook,in[j]+offset,&vd->opb,
+ samples_per_partition,-8)==-1)
+ goto eopbreak;
+ }else{
+ if(vorbis_book_decodevs_add(stagebook,in[j]+offset,&vd->opb,
+ samples_per_partition,-8)==-1)
+ goto eopbreak;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }else{
+ int max=(pcmend*ch)>>1;
+ int end=(info->end<max?info->end:max);
+ int n=end-info->begin;
+
+ if(n>0){
+ int partvals=n/samples_per_partition;
+ int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
+
+ char *partword=
+ (char *)alloca(partwords*partitions_per_word*sizeof(*partword));
+ int beginoff=info->begin/ch;
+
+ for(i=0;i<ch;i++)if(nonzero[i])break;
+ if(i==ch)return(0); /* no nonzero vectors */
+
+ samples_per_partition/=ch;
+
+ for(s=0;s<info->stages;s++){
for(i=0;i<partvals;){
+
if(s==0){
- /* fetch the partition word for each channel */
-
- partword[0][i+partitions_per_word-1]=1;
+ int temp;
+ partword[i+partitions_per_word-1]=1;
for(k=partitions_per_word-2;k>=0;k--)
- partword[0][i+k]=partword[0][i+k+1]*info->partitions;
+ partword[i+k]=partword[i+k+1]*info->partitions;
- for(j=1;j<ch;j++)
- for(k=partitions_per_word-1;k>=0;k--)
- partword[j][i+k]=partword[j-1][i+k];
+ /* fetch the partition word */
+ temp=vorbis_book_decode(phrasebook,&vd->opb);
+ if(oggpack_eop(&vd->opb))goto eopbreak;
- for(j=0;j<ch;j++){
- int temp=vorbis_book_decode(phrasebook,&vd->opb);
- if(oggpack_eop(&vd->opb))goto eopbreak;
-
- /* this can be done quickly in assembly due to the quotient
- always being at most six bits */
- for(k=0;k<partitions_per_word;k++){
- ogg_uint32_t div=partword[j][i+k];
- partword[j][i+k]=temp/div;
- temp-=partword[j][i+k]*div;
- }
-
+ /* this can be done quickly in assembly due to the quotient
+ always being at most six bits */
+ for(k=0;k<partitions_per_word;k++){
+ ogg_uint32_t div=partword[i+k];
+ partword[i+k]=temp/div;
+ temp-=partword[i+k]*div;
}
}
/* now we decode residual values for the partitions */
for(k=0;k<partitions_per_word && i<partvals;k++,i++)
- for(j=0;j<ch;j++){
- long offset=info->begin+i*samples_per_partition;
- if(info->stagemasks[partword[j][i]]&(1<<s)){
- codebook *stagebook=ci->book_param+
- info->stagebooks[(partword[j][i]<<3)+s];
- if(info->type){
- if(vorbis_book_decodev_add(stagebook,in[j]+offset,&vd->opb,
- samples_per_partition,-8)==-1)
- goto eopbreak;
- }else{
- if(vorbis_book_decodevs_add(stagebook,in[j]+offset,&vd->opb,
- samples_per_partition,-8)==-1)
- goto eopbreak;
- }
- }
+ if(info->stagemasks[partword[i]]&(1<<s)){
+ codebook *stagebook=ci->book_param+
+ info->stagebooks[(partword[i]<<3)+s];
+ if(vorbis_book_decodevv_add(stagebook,in,
+ i*samples_per_partition+beginoff,ch,
+ &vd->opb,
+ samples_per_partition,-8)==-1)
+ goto eopbreak;
}
}
}
}
- }else{
-
- char *partword=
- (char *)alloca(partwords*partitions_per_word*sizeof(*partword));
- int beginoff=info->begin/ch;
-
- for(i=0;i<ch;i++)if(nonzero[i])break;
- if(i==ch)return(0); /* no nonzero vectors */
-
- samples_per_partition/=ch;
-
- for(s=0;s<info->stages;s++){
- for(i=0;i<partvals;){
-
- if(s==0){
- int temp;
- partword[i+partitions_per_word-1]=1;
- for(k=partitions_per_word-2;k>=0;k--)
- partword[i+k]=partword[i+k+1]*info->partitions;
-
- /* fetch the partition word */
- temp=vorbis_book_decode(phrasebook,&vd->opb);
- if(oggpack_eop(&vd->opb))goto eopbreak;
-
- /* this can be done quickly in assembly due to the quotient
- always being at most six bits */
- for(k=0;k<partitions_per_word;k++){
- ogg_uint32_t div=partword[i+k];
- partword[i+k]=temp/div;
- temp-=partword[i+k]*div;
- }
- }
-
- /* now we decode residual values for the partitions */
- for(k=0;k<partitions_per_word && i<partvals;k++,i++)
- if(info->stagemasks[partword[i]]&(1<<s)){
- codebook *stagebook=ci->book_param+
- info->stagebooks[(partword[i]<<3)+s];
- if(vorbis_book_decodevv_add(stagebook,in,
- i*samples_per_partition+beginoff,ch,
- &vd->opb,
- samples_per_partition,-8)==-1)
- goto eopbreak;
- }
- }
- }
}
-
errout:
eopbreak: