[xiph-commits] r13158 - branches/lowmem-no-byte/Tremor

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Wed Jun 20 21:59:45 PDT 2007


Author: xiphmont
Date: 2007-06-20 21:59:44 -0700 (Wed, 20 Jun 2007)
New Revision: 13158

Added:
   branches/lowmem-no-byte/Tremor/dsp.c
Modified:
   branches/lowmem-no-byte/Tremor/floor1.c
   branches/lowmem-no-byte/Tremor/res012.c
Log:
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.



Added: branches/lowmem-no-byte/Tremor/dsp.c
===================================================================
--- branches/lowmem-no-byte/Tremor/dsp.c	                        (rev 0)
+++ branches/lowmem-no-byte/Tremor/dsp.c	2007-06-21 04:59:44 UTC (rev 13158)
@@ -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);
+}

Modified: branches/lowmem-no-byte/Tremor/floor1.c
===================================================================
--- branches/lowmem-no-byte/Tremor/floor1.c	2007-06-21 04:51:56 UTC (rev 13157)
+++ branches/lowmem-no-byte/Tremor/floor1.c	2007-06-21 04:59:44 UTC (rev 13158)
@@ -171,7 +171,7 @@
   }
 }
 
-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 @@
   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 @@
 	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;

Modified: branches/lowmem-no-byte/Tremor/res012.c
===================================================================
--- branches/lowmem-no-byte/Tremor/res012.c	2007-06-21 04:51:56 UTC (rev 13157)
+++ branches/lowmem-no-byte/Tremor/res012.c	2007-06-21 04:59:44 UTC (rev 13158)
@@ -96,121 +96,135 @@
   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(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:
   



More information about the commits mailing list