* 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-2009 *
- * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
+ * by the Xiph.Org Foundation https://xiph.org/ *
* *
********************************************************************
function: PCM data vector blocking, windowing and dis/reassembly
- last mod: $Id$
Handle windowing, overlap-add, etc of the PCM vectors. This is made
more amusing by Vorbis' current two allowed block sizes.
#include "registry.h"
#include "misc.h"
-static int ilog2(unsigned int v){
- int ret=0;
- if(v)--v;
- while(v){
- ret++;
- v>>=1;
- }
- return(ret);
-}
-
/* pcm accumulator examples (not exhaustive):
<-------------- lW ---------------->
private_state *b=NULL;
int hs;
- if(ci==NULL) return 1;
+ if(ci==NULL||
+ ci->modes<=0||
+ ci->blocksizes[0]<64||
+ ci->blocksizes[1]<ci->blocksizes[0]){
+ return 1;
+ }
hs=ci->halfrate_flag;
memset(v,0,sizeof(*v));
b=v->backend_state=_ogg_calloc(1,sizeof(*b));
v->vi=vi;
- b->modebits=ilog2(ci->modes);
+ b->modebits=ov_ilog(ci->modes-1);
b->transform[0]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[0]));
b->transform[1]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[1]));
mdct_init(b->transform[1][0],ci->blocksizes[1]>>hs);
/* Vorbis I uses only window type 0 */
- b->window[0]=ilog2(ci->blocksizes[0])-6;
- b->window[1]=ilog2(ci->blocksizes[1])-6;
+ /* note that the correct computation below is technically:
+ b->window[0]=ov_ilog(ci->blocksizes[0]-1)-6;
+ b->window[1]=ov_ilog(ci->blocksizes[1]-1)-6;
+ but since blocksizes are always powers of two,
+ the below is equivalent.
+ */
+ b->window[0]=ov_ilog(ci->blocksizes[0])-7;
+ b->window[1]=ov_ilog(ci->blocksizes[1])-7;
if(encp){ /* encode/decode differ here */
if(v->lW){
if(v->W){
/* large/large */
- float *w=_vorbis_window_get(b->window[1]-hs);
+ const float *w=_vorbis_window_get(b->window[1]-hs);
float *pcm=v->pcm[j]+prevCenter;
float *p=vb->pcm[j];
for(i=0;i<n1;i++)
pcm[i]=pcm[i]*w[n1-i-1] + p[i]*w[i];
}else{
/* large/small */
- float *w=_vorbis_window_get(b->window[0]-hs);
+ const float *w=_vorbis_window_get(b->window[0]-hs);
float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
float *p=vb->pcm[j];
for(i=0;i<n0;i++)
}else{
if(v->W){
/* small/large */
- float *w=_vorbis_window_get(b->window[0]-hs);
+ const float *w=_vorbis_window_get(b->window[0]-hs);
float *pcm=v->pcm[j]+prevCenter;
float *p=vb->pcm[j]+n1/2-n0/2;
for(i=0;i<n0;i++)
pcm[i]=p[i];
}else{
/* small/small */
- float *w=_vorbis_window_get(b->window[0]-hs);
+ const float *w=_vorbis_window_get(b->window[0]-hs);
float *pcm=v->pcm[j]+prevCenter;
float *p=vb->pcm[j];
for(i=0;i<n0;i++)
if(b->sample_count>v->granulepos){
/* corner case; if this is both the first and last audio page,
then spec says the end is cut, not beginning */
+ long extra=b->sample_count-vb->granulepos;
+
+ /* we use ogg_int64_t for granule positions because a
+ uint64 isn't universally available. Unfortunately,
+ that means granposes can be 'negative' and result in
+ extra being negative */
+ if(extra<0)
+ extra=0;
+
if(vb->eofflag){
/* trim the end */
/* no preceding granulepos; assume we started at zero (we'd
/* granulepos could be -1 due to a seek, but that would result
in a long count, not short count */
- v->pcm_current-=(b->sample_count-v->granulepos)>>hs;
+ /* Guard against corrupt/malicious frames that set EOP and
+ a backdated granpos; don't rewind more samples than we
+ actually have */
+ if(extra > (v->pcm_current - v->pcm_returned)<<hs)
+ extra = (v->pcm_current - v->pcm_returned)<<hs;
+
+ v->pcm_current-=extra>>hs;
}else{
/* trim the beginning */
- v->pcm_returned+=(b->sample_count-v->granulepos)>>hs;
+ v->pcm_returned+=extra>>hs;
if(v->pcm_returned>v->pcm_current)
v->pcm_returned=v->pcm_current;
}
if(extra)
if(vb->eofflag){
/* partial last frame. Strip the extra samples off */
+
+ /* Guard against corrupt/malicious frames that set EOP and
+ a backdated granpos; don't rewind more samples than we
+ actually have */
+ if(extra > (v->pcm_current - v->pcm_returned)<<hs)
+ extra = (v->pcm_current - v->pcm_returned)<<hs;
+
+ /* we use ogg_int64_t for granule positions because a
+ uint64 isn't universally available. Unfortunately,
+ that means granposes can be 'negative' and result in
+ extra being negative */
+ if(extra<0)
+ extra=0;
+
v->pcm_current-=extra>>hs;
} /* else {Shouldn't happen *unless* the bitstream is out of
spec. Either way, believe the bitstream } */
}
-float *vorbis_window(vorbis_dsp_state *v,int W){
+const float *vorbis_window(vorbis_dsp_state *v,int W){
vorbis_info *vi=v->vi;
codec_setup_info *ci=vi->codec_setup;
int hs=ci->halfrate_flag;