• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /************************************************************************
2   * Copyright (C) 2002-2009, Xiph.org Foundation
3   * Copyright (C) 2010, Robin Watts for Pinknoise Productions Ltd
4   * All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions
8   * are met:
9   *
10   *     * Redistributions of source code must retain the above copyright
11   * notice, this list of conditions and the following disclaimer.
12   *     * Redistributions in binary form must reproduce the above
13   * copyright notice, this list of conditions and the following disclaimer
14   * in the documentation and/or other materials provided with the
15   * distribution.
16   *     * Neither the names of the Xiph.org Foundation nor Pinknoise
17   * Productions Ltd nor the names of its contributors may be used to
18   * endorse or promote products derived from this software without
19   * specific prior written permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   ************************************************************************
33  
34   function: PCM data vector blocking, windowing and dis/reassembly
35  
36   ************************************************************************/
37  
38  #include <stdlib.h>
39  #include "ogg.h"
40  #include "mdct.h"
41  #include "ivorbiscodec.h"
42  #include "codec_internal.h"
43  #include "misc.h"
44  #include "window_lookup.h"
45  
vorbis_dsp_restart(vorbis_dsp_state * v)46  int vorbis_dsp_restart(vorbis_dsp_state *v){
47    if(!v)return -1;
48    {
49      vorbis_info *vi=v->vi;
50      codec_setup_info *ci;
51  
52      if(!vi)return -1;
53      ci=vi->codec_setup;
54      if(!ci)return -1;
55  
56      v->out_end=-1;
57      v->out_begin=-1;
58  
59      v->granulepos=-1;
60      v->sequence=-1;
61      v->sample_count=-1;
62    }
63    return 0;
64  }
65  
vorbis_dsp_init(vorbis_dsp_state * v,vorbis_info * vi)66  int vorbis_dsp_init(vorbis_dsp_state *v,vorbis_info *vi){
67    int i;
68  
69    codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
70  
71    v->vi=vi;
72  
73    v->work=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->work));
74    v->mdctright=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->mdctright));
75    for(i=0;i<vi->channels;i++){
76      v->work[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>1)*
77  					  sizeof(*v->work[i]));
78      v->mdctright[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>2)*
79  					       sizeof(*v->mdctright[i]));
80    }
81  
82    v->lW=0; /* previous window size */
83    v->W=0;  /* current window size */
84  
85    vorbis_dsp_restart(v);
86    return 0;
87  }
88  
vorbis_dsp_create(vorbis_info * vi)89  vorbis_dsp_state *vorbis_dsp_create(vorbis_info *vi){
90    vorbis_dsp_state *v=_ogg_calloc(1,sizeof(*v));
91    vorbis_dsp_init(v,vi);
92    return v;
93  }
94  
vorbis_dsp_clear(vorbis_dsp_state * v)95  void vorbis_dsp_clear(vorbis_dsp_state *v){
96    int i;
97    if(v){
98      vorbis_info *vi=v->vi;
99  
100      if(v->work){
101        for(i=0;i<vi->channels;i++)
102          if(v->work[i])_ogg_free(v->work[i]);
103        _ogg_free(v->work);
104      }
105      if(v->mdctright){
106        for(i=0;i<vi->channels;i++)
107          if(v->mdctright[i])_ogg_free(v->mdctright[i]);
108        _ogg_free(v->mdctright);
109      }
110    }
111  }
112  
vorbis_dsp_destroy(vorbis_dsp_state * v)113  void vorbis_dsp_destroy(vorbis_dsp_state *v){
114    vorbis_dsp_clear(v);
115    _ogg_free(v);
116  }
117  
_vorbis_window(int left)118  static LOOKUP_T *_vorbis_window(int left){
119    switch(left){
120    case 32:
121      return vwin64;
122    case 64:
123      return vwin128;
124    case 128:
125      return vwin256;
126    case 256:
127      return vwin512;
128    case 512:
129      return vwin1024;
130    case 1024:
131      return vwin2048;
132    case 2048:
133      return vwin4096;
134  #ifndef LIMIT_TO_64kHz
135    case 4096:
136      return vwin8192;
137  #endif
138    default:
139      return(0);
140    }
141  }
142  
143  /* pcm==0 indicates we just want the pending samples, no more */
vorbis_dsp_pcmout(vorbis_dsp_state * v,ogg_int16_t * pcm,int samples)144  int vorbis_dsp_pcmout(vorbis_dsp_state *v,ogg_int16_t *pcm,int samples){
145    vorbis_info *vi=v->vi;
146    codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
147    if(v->out_begin>-1 && v->out_begin<v->out_end){
148      int n=v->out_end-v->out_begin;
149      if(pcm){
150        int i;
151        if(n>samples)n=samples;
152        for(i=0;i<vi->channels;i++)
153  	mdct_unroll_lap(ci->blocksizes[0],ci->blocksizes[1],
154  			v->lW,v->W,v->work[i],v->mdctright[i],
155  			_vorbis_window(ci->blocksizes[0]>>1),
156  			_vorbis_window(ci->blocksizes[1]>>1),
157  			pcm+i,vi->channels,
158  			v->out_begin,v->out_begin+n);
159      }
160      return(n);
161    }
162    return(0);
163  }
164  
vorbis_dsp_read(vorbis_dsp_state * v,int s)165  int vorbis_dsp_read(vorbis_dsp_state *v,int s){
166    if(s && v->out_begin+s>v->out_end)return(OV_EINVAL);
167    v->out_begin+=s;
168    return(0);
169  }
170  
vorbis_packet_blocksize(vorbis_info * vi,ogg_packet * op)171  long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
172    codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
173    oggpack_buffer       opb;
174    int                  mode;
175    int modebits=0;
176    int v=ci->modes;
177  
178    oggpack_readinit(&opb,op->packet);
179  
180    /* Check the packet type */
181    if(oggpack_read(&opb,1)!=0){
182      /* Oops.  This is not an audio data packet */
183      return(OV_ENOTAUDIO);
184    }
185  
186    while(v>1){
187      modebits++;
188      v>>=1;
189    }
190  
191    /* read our mode and pre/post windowsize */
192    mode=oggpack_read(&opb,modebits);
193    if(mode==-1)return(OV_EBADPACKET);
194    return(ci->blocksizes[ci->mode_param[mode].blockflag]);
195  }
196  
197  
ilog(ogg_uint32_t v)198  static int ilog(ogg_uint32_t v){
199    int ret=0;
200    if(v)--v;
201    while(v){
202      ret++;
203      v>>=1;
204    }
205    return(ret);
206  }
207  
vorbis_dsp_synthesis(vorbis_dsp_state * vd,ogg_packet * op,int decodep)208  int vorbis_dsp_synthesis(vorbis_dsp_state *vd,ogg_packet *op,int decodep){
209    vorbis_info          *vi=vd->vi;
210    codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
211    int                   mode,i;
212  
213    oggpack_readinit(&vd->opb,op->packet);
214  
215    /* Check the packet type */
216    if(oggpack_read(&vd->opb,1)!=0){
217      /* Oops.  This is not an audio data packet */
218      return OV_ENOTAUDIO ;
219    }
220  
221    /* read our mode and pre/post windowsize */
222    mode=oggpack_read(&vd->opb,ilog(ci->modes));
223    if(mode==-1 || mode>=ci->modes) return OV_EBADPACKET;
224  
225    /* shift information we still need from last window */
226    vd->lW=vd->W;
227    vd->W=ci->mode_param[mode].blockflag;
228    for(i=0;i<vi->channels;i++)
229      mdct_shift_right(ci->blocksizes[vd->lW],vd->work[i],vd->mdctright[i]);
230  
231    if(vd->W){
232      int temp;
233      oggpack_read(&vd->opb,1);
234      temp=oggpack_read(&vd->opb,1);
235      if(temp==-1) return OV_EBADPACKET;
236    }
237  
238    /* packet decode and portions of synthesis that rely on only this block */
239    if(decodep){
240      mapping_inverse(vd,ci->map_param+ci->mode_param[mode].mapping);
241  
242      if(vd->out_begin==-1){
243        vd->out_begin=0;
244        vd->out_end=0;
245      }else{
246        vd->out_begin=0;
247        vd->out_end=ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
248      }
249    }
250  
251    /* track the frame number... This is for convenience, but also
252       making sure our last packet doesn't end with added padding.
253  
254       This is not foolproof!  It will be confused if we begin
255       decoding at the last page after a seek or hole.  In that case,
256       we don't have a starting point to judge where the last frame
257       is.  For this reason, vorbisfile will always try to make sure
258       it reads the last two marked pages in proper sequence */
259  
260    /* if we're out of sequence, dump granpos tracking until we sync back up */
261    if(vd->sequence==-1 || vd->sequence+1 != op->packetno-3){
262      /* out of sequence; lose count */
263      vd->granulepos=-1;
264      vd->sample_count=-1;
265    }
266  
267    vd->sequence=op->packetno;
268    vd->sequence=vd->sequence-3;
269  
270    if(vd->sample_count==-1){
271      vd->sample_count=0;
272    }else{
273      vd->sample_count+=
274        ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
275    }
276  
277    if(vd->granulepos==-1){
278      if(op->granulepos!=-1){ /* only set if we have a
279  			       position to set to */
280  
281        vd->granulepos=op->granulepos;
282  
283        /* is this a short page? */
284        if(vd->sample_count>vd->granulepos){
285  	/* corner case; if this is both the first and last audio page,
286  	   then spec says the end is cut, not beginning */
287  	if(op->e_o_s){
288  	  /* trim the end */
289  	  /* no preceeding granulepos; assume we started at zero (we'd
290  	     have to in a short single-page stream) */
291  	  /* granulepos could be -1 due to a seek, but that would result
292  	     in a long coun t, not short count */
293  
294  	  vd->out_end-=(int)(vd->sample_count-vd->granulepos);
295  	}else{
296  	  /* trim the beginning */
297  	  vd->out_begin+=(int)(vd->sample_count-vd->granulepos);
298  	  if(vd->out_begin>vd->out_end)
299  	    vd->out_begin=vd->out_end;
300  	}
301  
302        }
303  
304      }
305    }else{
306      vd->granulepos+=
307        ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
308      if(op->granulepos!=-1 && vd->granulepos!=op->granulepos){
309  
310        if(vd->granulepos>op->granulepos){
311  	long extra=(long)(vd->granulepos-op->granulepos);
312  
313  	if(extra)
314  	  if(op->e_o_s){
315  	    /* partial last frame.  Strip the extra samples off */
316  	    vd->out_end-=extra;
317  	  } /* else {Shouldn't happen *unless* the bitstream is out of
318  	       spec.  Either way, believe the bitstream } */
319        } /* else {Shouldn't happen *unless* the bitstream is out of
320  	   spec.  Either way, believe the bitstream } */
321        vd->granulepos=op->granulepos;
322      }
323    }
324  
325    return(0);
326  }
327