| /************************************************************************ |
| * Copyright (C) 2002-2009, Xiph.org Foundation |
| * Copyright (C) 2010, Robin Watts for Pinknoise Productions Ltd |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the names of the Xiph.org Foundation nor Pinknoise |
| * Productions Ltd nor the names of its contributors may be used to |
| * endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| ************************************************************************ |
| |
| function: residue backend 0, 1 and 2 implementation |
| |
| ************************************************************************/ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <math.h> |
| #include "ogg.h" |
| #include "ivorbiscodec.h" |
| #include "codec_internal.h" |
| #include "codebook.h" |
| #include "misc.h" |
| #include "os.h" |
| |
| void res_clear_info(vorbis_info_residue *info){ |
| if(info){ |
| if(info->stagemasks)_ogg_free(info->stagemasks); |
| if(info->stagebooks)_ogg_free(info->stagebooks); |
| memset(info,0,sizeof(*info)); |
| } |
| } |
| |
| |
| /* vorbis_info is for range checking */ |
| int res_unpack(vorbis_info_residue *info, |
| vorbis_info *vi,oggpack_buffer *opb){ |
| int j,k; |
| codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
| memset(info,0,sizeof(*info)); |
| |
| info->type=oggpack_read(opb,16); |
| if(info->type>2 || info->type<0)goto errout; |
| info->begin=oggpack_read(opb,24); |
| info->end=oggpack_read(opb,24); |
| info->grouping=oggpack_read(opb,24)+1; // "partition size" in spec |
| info->partitions=(char)(oggpack_read(opb,6)+1); // "classification" in spec |
| info->groupbook=(unsigned char)oggpack_read(opb,8); // "classbook" in spec |
| if(info->groupbook>=ci->books)goto errout; |
| |
| info->stagemasks=_ogg_malloc(info->partitions*sizeof(*info->stagemasks)); |
| info->stagebooks=_ogg_malloc(info->partitions*8*sizeof(*info->stagebooks)); |
| |
| for(j=0;j<info->partitions;j++){ |
| int cascade=oggpack_read(opb,3); |
| if(oggpack_read(opb,1)) |
| cascade|=(oggpack_read(opb,5)<<3); |
| info->stagemasks[j]=cascade; |
| } |
| |
| for(j=0;j<info->partitions;j++){ |
| for(k=0;k<8;k++){ |
| if((info->stagemasks[j]>>k)&1){ |
| unsigned char book=(unsigned char)oggpack_read(opb,8); |
| if(book>=ci->books)goto errout; |
| info->stagebooks[j*8+k]=book; |
| if(k+1>info->stages)info->stages=k+1; |
| }else |
| info->stagebooks[j*8+k]=0xff; |
| } |
| } |
| |
| if(oggpack_eop(opb))goto errout; |
| |
| // According to the Vorbis spec (paragraph 8.6.2 "packet decode"), residue |
| // begin and end should be limited to the maximum possible vector size in |
| // case they exceed it. However doing that makes the decoder crash further |
| // down, so we return an error instead. |
| int limit = (info->type == 2 ? vi->channels : 1) * ci->blocksizes[1] / 2; |
| if (info->begin > info->end || |
| info->end > limit) { |
| goto errout; |
| } |
| return 0; |
| errout: |
| res_clear_info(info); |
| return 1; |
| } |
| |
| int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info, |
| ogg_int32_t **in,int *nonzero,int ch){ |
| |
| int i,j,k,s,used=0; |
| codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup; |
| codebook *phrasebook=ci->book_param+info->groupbook; |
| int samples_per_partition=info->grouping; |
| int partitions_per_word=phrasebook->dim; |
| int pcmend=ci->blocksizes[vd->W]; |
| |
| if(info->type<2){ |
| 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; |
| |
| for(i=0;i<ch;i++) |
| if(nonzero[i]) |
| in[used++]=in[i]; |
| ch=used; |
| |
| if(used){ |
| |
| char **partword=(char **)_ogg_calloc(ch,sizeof(*partword)); |
| if(partword==NULL)goto cleanup1; |
| for(j=0;j<ch;j++){ |
| partword[j]=(char *)_ogg_malloc(partwords*partitions_per_word* |
| sizeof(*partword[j])); |
| if(partword[j]==NULL)goto cleanup1; |
| } |
| |
| 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(temp==-1)goto cleanup1; |
| |
| /* 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]= (div == 0) ? 0 : (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; |
| int idx = (int)partword[j][i]; |
| if(idx < info->partitions && info->stagemasks[idx]&(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 cleanup1; |
| }else{ |
| if(vorbis_book_decodevs_add(stagebook,in[j]+offset,&vd->opb, |
| samples_per_partition,-8)==-1) |
| goto cleanup1; |
| } |
| } |
| } |
| } |
| } |
| cleanup1: |
| if(partword){ |
| for(j=0;j<ch;j++){ |
| if(partword[j])_ogg_free(partword[j]); |
| } |
| _ogg_free(partword); |
| } |
| } |
| } |
| }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 *)_ogg_malloc(partwords*partitions_per_word*sizeof(*partword)); |
| if(partword==NULL)goto cleanup2; |
| int beginoff=info->begin/ch; |
| |
| for(i=0;i<ch;i++)if(nonzero[i])break; |
| if(i==ch)goto cleanup2; /* 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(temp==-1)goto cleanup2; |
| |
| /* 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]= (div == 0) ? 0 : (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(partword[i] >= 0 && partword[i] < info->partitions && |
| (info->stagemasks[(int)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 cleanup2; |
| } |
| } |
| } |
| } |
| cleanup2: |
| if(partword)_ogg_free(partword); |
| } |
| } |
| |
| return 0; |
| } |
| |