Skip to content
Snippets Groups Projects
vorbis.c 50 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
                AV_DEBUG(" dy %d  adx %d base %d = %d \n", dy, adx, base, dy/adx);
    
                x=lx;
                y=ly;
                err=0;
                if (dy<0) {
                    sy=base-1;
                } else {
                    sy=base+1;
                }
                ady=ady-(base<0 ? -base : base)*adx;
                vec[x]=floor1_inverse_db_table[y];
    
                AV_DEBUG(" vec[ %d ] = %d \n", x, y);
    
                for(x=lx+1;(x<hx) && (x<vf->x_list[1]);++x) {
                    err+=ady;
                    if (err>=adx) {
                        err-=adx;
                        y+=sy;
                    } else {
                        y+=base;
                    }
                    vec[x]=floor1_inverse_db_table[y];
    
                    AV_DEBUG(" vec[ %d ] = %d \n", x, y);
                }
    
    /*            for(j=1;j<hx-lx+1;++j) {  // iterating render_point
                    dy=hy-ly;
                    adx=hx-lx;
                    ady= dy<0 ? -dy : dy;
                    err=ady*j;
                    off=err/adx;
                    if (dy<0) {
                        predicted=ly-off;
                    } else {
                        predicted=ly+off;
                    }
                    if (lx+j < vf->x_list[1]) {
                        vec[lx+j]=floor1_inverse_db_table[predicted];
                    }
                }*/
    
                lx=hx;
                ly=hy;
            }
        }
    
        if (hx<vf->x_list[1]) {
            for(i=hx;i<vf->x_list[1];++i) {
                vec[i]=floor1_inverse_db_table[hy];
            }
        }
    
        AV_DEBUG(" Floor decoded\n");
    
        return 0;
    }
    
    // Read and decode residue
    
    static int vorbis_residue_decode(vorbis_context *vc, vorbis_residue *vr, uint_fast8_t ch, uint_fast8_t *do_not_decode, float *vec, uint_fast16_t vlen) {
        GetBitContext *gb=&vc->gb;
        uint_fast8_t c_p_c=vc->codebooks[vr->classbook].dimensions;
        uint_fast16_t n_to_read=vr->end-vr->begin;
        uint_fast16_t ptns_to_read=n_to_read/vr->partition_size;
    
        uint_fast8_t classifs[ptns_to_read*vc->audio_channels];
    
        uint_fast8_t pass;
        uint_fast8_t ch_used;
        uint_fast8_t i,j,l;
        uint_fast16_t k;
    
        if (vr->type==2) {
            for(j=1;j<ch;++j) {
                    do_not_decode[0]&=do_not_decode[j];  // FIXME - clobbering input
            }
            if (do_not_decode[0]) return 0;
            ch_used=1;
        } else {
            ch_used=ch;
        }
    
        AV_DEBUG(" residue type 0/1/2 decode begin, ch: %d  cpc %d  \n", ch, c_p_c);
    
        for(pass=0;pass<=vr->maxpass;++pass) { // FIXME OPTIMIZE?
            uint_fast16_t voffset;
            uint_fast16_t partition_count;
            uint_fast16_t j_times_ptns_to_read;
    
            voffset=vr->begin;
            for(partition_count=0;partition_count<ptns_to_read;) {  // SPEC        error
                if (!pass) {
                    for(j_times_ptns_to_read=0, j=0;j<ch_used;++j) {
                        if (!do_not_decode[j]) {
                            uint_fast32_t temp=get_vlc2(gb, vc->codebooks[vr->classbook].vlc.table,
                            V_NB_BITS, vc->codebooks[vr->classbook].maxdepth);
    
                            AV_DEBUG("Classword: %d \n", temp);
    
                            for(i=0;i<c_p_c;++i) {
                                uint_fast32_t temp2;
    
                                temp2=temp/vr->classifications;
                                classifs[j_times_ptns_to_read+partition_count+c_p_c-1-i]=temp-temp2*vr->classifications;
                                temp=temp2;
                            }
                        }
                        j_times_ptns_to_read+=ptns_to_read;
                    }
                }
                for(i=0;(i<c_p_c) && (partition_count<ptns_to_read);++i) {
                    for(j_times_ptns_to_read=0, j=0;j<ch_used;++j) {
                        uint_fast16_t voffs;
    
                        if (!do_not_decode[j]) {
                            uint_fast8_t vqclass=classifs[j_times_ptns_to_read+partition_count];
                            int_fast16_t vqbook=vr->books[vqclass][pass];
    
                            if (vqbook>=0) {
                                uint_fast16_t coffs;
    
                                if (vr->type==0) {
                                    uint_fast16_t step=vr->partition_size/vc->codebooks[vqbook].dimensions;
    
                                    voffs=voffset+j*vlen;
                                    for(k=0;k<step;++k) {
                                        coffs=get_vlc2(gb, vc->codebooks[vqbook].vlc.table,
                                        V_NB_BITS, vc->codebooks[vr->classbook].maxdepth) * vc->codebooks[vqbook].dimensions;
                                        for(l=0;l<vc->codebooks[vqbook].dimensions;++l) {
                                            vec[voffs+k+l*step]+=vc->codebooks[vqbook].codevectors[coffs+l];  // FPMATH
                                        }
                                    }
                                }
                                else if (vr->type==1) {
                                    voffs=voffset+j*vlen;
                                    for(k=0;k<vr->partition_size/vc->codebooks[vqbook].dimensions;++k) {
                                        coffs=get_vlc2(gb, vc->codebooks[vqbook].vlc.table,
                                        V_NB_BITS, vc->codebooks[vr->classbook].maxdepth) * vc->codebooks[vqbook].dimensions;
                                        for(l=0;l<vc->codebooks[vqbook].dimensions;++l, ++voffs) {
                                            vec[voffs]+=vc->codebooks[vqbook].codevectors[coffs+l];  // FPMATH
    
                                            AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d  \n", pass, voffs, vec[voffs], vc->codebooks[vqbook].codevectors[coffs+l], coffs);
                                        }
                                    }
                                }
                                else if (vr->type==2 && ch==2) { // most frequent case optimized
                                    voffs=voffset;
    
                                    for(k=0;k<vr->partition_size/vc->codebooks[vqbook].dimensions;++k) {
                                        coffs=get_vlc2(gb, vc->codebooks[vqbook].vlc.table,
                                        V_NB_BITS, vc->codebooks[vr->classbook].maxdepth) * vc->codebooks[vqbook].dimensions;
                                        for(l=0;l<vc->codebooks[vqbook].dimensions;++l, ++voffs) {
                                            vec[(voffs>>1)+((voffs&1) ? vlen : 0)]+=vc->codebooks[vqbook].codevectors[coffs+l];  // FPMATH
    
                                            AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d+%d  \n", pass, voffset/ch+(voffs%ch)*vlen, vec[voffset/ch+(voffs%ch)*vlen], vc->codebooks[vqbook].codevectors[coffs+l], coffs, l);
                                        }
                                    }
    
                                }
                                else if (vr->type==2) {
                                    voffs=voffset;
    
                                    for(k=0;k<vr->partition_size/vc->codebooks[vqbook].dimensions;++k) {
                                        coffs=get_vlc2(gb, vc->codebooks[vqbook].vlc.table,
                                        V_NB_BITS, vc->codebooks[vr->classbook].maxdepth) * vc->codebooks[vqbook].dimensions;
                                        for(l=0;l<vc->codebooks[vqbook].dimensions;++l, ++voffs) {
                                            vec[voffs/ch+(voffs%ch)*vlen]+=vc->codebooks[vqbook].codevectors[coffs+l];  // FPMATH FIXME use if and counter instead of / and %
    
                                            AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d+%d  \n", pass, voffset/ch+(voffs%ch)*vlen, vec[voffset/ch+(voffs%ch)*vlen], vc->codebooks[vqbook].codevectors[coffs+l], coffs, l);
                                        }
                                    }
                                } else {
                                    av_log(vc->avccontext, AV_LOG_ERROR, " Invalid residue type while residue decode?! \n");
                                    return 1;
                                }
                            }
                        }
    
                        j_times_ptns_to_read+=ptns_to_read;
    
                    }
                    ++partition_count;
                    voffset+=vr->partition_size;
                }
            }
        }
        return 0;
    }
    
    // Decode the audio packet using the functions above
    
    #define BIAS 384
    
    
    static int vorbis_parse_audio_packet(vorbis_context *vc) {
        GetBitContext *gb=&vc->gb;
    
        uint_fast8_t previous_window=0,next_window=0;
        uint_fast8_t mode_number;
        uint_fast16_t blocksize;
        int_fast32_t i,j;
        uint_fast8_t no_residue[vc->audio_channels];
        uint_fast8_t do_not_decode[vc->audio_channels];
        vorbis_mapping *mapping;
        float *ch_res_ptr=vc->channel_residues;
        float *ch_floor_ptr=vc->channel_floors;
        uint_fast8_t res_chan[vc->audio_channels];
        uint_fast8_t res_num=0;
        int_fast16_t retlen=0;
        uint_fast16_t saved_start=0;
    
        if (get_bits1(gb)) {
            av_log(vc->avccontext, AV_LOG_ERROR, "Not a Vorbis I audio packet.\n");
            return -1; // packet type not audio
        }
    
    
        if (vc->mode_count==1) {
            mode_number=0;
        } else {
            mode_number=get_bits(gb, ilog(vc->mode_count-1));
        }
    
        mapping=&vc->mappings[vc->modes[mode_number].mapping];
    
        AV_DEBUG(" Mode number: %d , mapping: %d , blocktype %d \n", mode_number, vc->modes[mode_number].mapping, vc->modes[mode_number].blockflag);
    
        if (vc->modes[mode_number].blockflag) {
            previous_window=get_bits1(gb);
            next_window=get_bits1(gb);
        }
    
        blocksize=vc->modes[mode_number].blockflag ? vc->blocksize_1 : vc->blocksize_0;
        memset(ch_res_ptr, 0, sizeof(float)*vc->audio_channels*blocksize/2); //FIXME can this be removed ?
        memset(ch_floor_ptr, 0, sizeof(float)*vc->audio_channels*blocksize/2); //FIXME can this be removed ?
    
    // Decode floor(1)
    
        for(i=0;i<vc->audio_channels;++i) {
            vorbis_floor *floor;
            if (mapping->submaps>1) {
                floor=&vc->floors[mapping->submap_floor[mapping->mux[i]]];
            } else {
                floor=&vc->floors[mapping->submap_floor[0]];
            }
    
            no_residue[i]=vorbis_floor1_decode(vc, floor, ch_floor_ptr);
            ch_floor_ptr+=blocksize/2;
        }
    
    // Nonzero vector propagate
    
        for(i=mapping->coupling_steps-1;i>=0;--i) {
            if (!(no_residue[mapping->magnitude[i]] & no_residue[mapping->angle[i]])) {
                no_residue[mapping->magnitude[i]]=0;
                no_residue[mapping->angle[i]]=0;
            }
        }
    
    // Decode residue
    
        for(i=0;i<mapping->submaps;++i) {
            vorbis_residue *residue;
            uint_fast8_t ch=0;
    
            for(j=0;j<vc->audio_channels;++j) {
                if ((mapping->submaps==1) || (i=mapping->mux[j])) {
                    res_chan[j]=res_num;
                    if (no_residue[j]) {
                        do_not_decode[ch]=1;
                    } else {
                        do_not_decode[ch]=0;
                    }
                    ++ch;
                    ++res_num;
                }
            }
            residue=&vc->residues[mapping->submap_residue[i]];
            vorbis_residue_decode(vc, residue, ch, do_not_decode, ch_res_ptr, blocksize/2);
    
            ch_res_ptr+=ch*blocksize/2;
        }
    
    // Inverse coupling
    
        for(i=mapping->coupling_steps-1;i>=0;--i) { //warning: i has to be signed
            float *mag, *ang;
    
            mag=vc->channel_residues+res_chan[mapping->magnitude[i]]*blocksize/2;
            ang=vc->channel_residues+res_chan[mapping->angle[i]]*blocksize/2;
            for(j=0;j<blocksize/2;++j) {
                float temp;
                if (mag[j]>0.0) {
                    if (ang[j]>0.0) {
                        ang[j]=mag[j]-ang[j];
                    } else {
                        temp=ang[j];
                        ang[j]=mag[j];
                        mag[j]+=temp;
                    }
                } else {
                    if (ang[j]>0.0) {
                        ang[j]+=mag[j];
                    } else {
                        temp=ang[j];
                        ang[j]=mag[j];
                        mag[j]-=temp;
                    }
                }
            }
        }
    
    // Dotproduct
    
        for(j=0, ch_floor_ptr=vc->channel_floors;j<vc->audio_channels;++j,ch_floor_ptr+=blocksize/2) {
            ch_res_ptr=vc->channel_residues+res_chan[j]*blocksize/2;
    
            for(i=0;i<blocksize/2;++i) {
                ch_floor_ptr[i]*=ch_res_ptr[i]; //FPMATH
            }
        }
    
    // MDCT, overlap/add, save data for next overlapping  FPMATH
    
        for(j=0;j<vc->audio_channels;++j) {
            uint_fast8_t step=vc->audio_channels;
            uint_fast16_t k;
            float *saved=vc->saved+j*vc->blocksize_1/2;
            float *ret=vc->ret;
            const float *lwin=vc->lwin;
            const float *swin=vc->swin;
    
            float *buf=vc->buf;
            float *buf_tmp=vc->buf_tmp;
    
    
            ch_floor_ptr=vc->channel_floors+j*blocksize/2;
    
            saved_start=vc->saved_start;
    
            ff_imdct_calc(vc->modes[mode_number].blockflag ? &vc->mdct1 : &vc->mdct0, buf, ch_floor_ptr, buf_tmp);
    
            if (vc->modes[mode_number].blockflag) {
                // -- overlap/add
                if (previous_window) {
                    for(k=j, i=0;i<vc->blocksize_1/2;++i, k+=step) {
    
                        ret[k]=saved[i]+buf[i]*lwin[i]+BIAS;
    
                    }
                    retlen=vc->blocksize_1/2;
                } else {
                    for(k=j, i=0;i<vc->blocksize_0/2;++i, k+=step) {
    
                        ret[k]=saved[i]+buf[(vc->blocksize_1-vc->blocksize_0)/4+i]*swin[i]+BIAS;
    
                    }
                    for(i=0;i<(vc->blocksize_1-vc->blocksize_0)/4;++i, k+=step) {
    
                        ret[k]=buf[vc->blocksize_0/2+(vc->blocksize_1-vc->blocksize_0)/4+i]+BIAS;
    
                    }
                    retlen=vc->blocksize_0/2+(vc->blocksize_1-vc->blocksize_0)/4;
                }
                // -- save
                if (next_window) {
                    for(i=0;i<vc->blocksize_1/2;++i) {
                        saved[i]=buf[vc->blocksize_1/2+i]*lwin[vc->blocksize_1/2-1-i];
                    }
                    saved_start=0;
                } else {
                    saved_start=(vc->blocksize_1-vc->blocksize_0)/4;
                    for(i=0;i<saved_start;++i) {
                        saved[i]=buf[vc->blocksize_1/2+i];
                    }
                    for(i=0;i<vc->blocksize_0/2;++i) {
                        saved[saved_start+i]=buf[vc->blocksize_1/2+saved_start+i]*swin[vc->blocksize_0/2-1-i];
                    }
                }
            } else {
                // --overlap/add
                for(k=j, i=0;i<saved_start;++i, k+=step) {
    
                    ret[k]=saved[i]+BIAS;
    
                }
                for(i=0;i<vc->blocksize_0/2;++i, k+=step) {
    
                    ret[k]=saved[saved_start+i]+buf[i]*swin[i]+BIAS;
    
                }
                retlen=saved_start+vc->blocksize_0/2;
                // -- save
                for(i=0;i<vc->blocksize_0/2;++i) {
                    saved[i]=buf[vc->blocksize_0/2+i]*swin[vc->blocksize_0/2-1-i];
                }
                saved_start=0;
            }
        }
        vc->saved_start=saved_start;
    
        return retlen*vc->audio_channels;
    }
    
    // Return the decoded audio packet through the standard api
    
    static int vorbis_decode_frame(AVCodecContext *avccontext,
                            void *data, int *data_size,
                            uint8_t *buf, int buf_size)
    {
        vorbis_context *vc = avccontext->priv_data ;
        GetBitContext *gb = &(vc->gb);
    
        int_fast16_t i, len;
    
        if(!buf_size){
            return 0;
        }
    
        AV_DEBUG("packet length %d \n", buf_size);
    
        init_get_bits(gb, buf, buf_size*8);
    
        len=vorbis_parse_audio_packet(vc);
    
        if (len<=0) {
            *data_size=0;
            return buf_size;
        }
    
        if (!vc->first_frame) {
            vc->first_frame=1;
            *data_size=0;
            return buf_size ;
        }
    
        AV_DEBUG("parsed %d bytes %d bits, returned %d samples (*ch*bits) \n", get_bits_count(gb)/8, get_bits_count(gb)%8, len);
    
        for(i=0;i<len;++i) {
    
            int_fast32_t tmp= ((int32_t*)vc->ret)[i];
            if(tmp > 0x43c07fff)
                tmp= 32767;
            else if(tmp < 0x43bf8000)
                tmp= -32768;
    
        *data_size=len*2;
    
        return buf_size ;
    }
    
    // Close decoder
    
    static int vorbis_decode_close(AVCodecContext *avccontext) {
        vorbis_context *vc = avccontext->priv_data;
    
        vorbis_free(vc);
    
        return 0 ;
    }
    
    AVCodec vorbis_decoder = {
        "vorbis",
        CODEC_TYPE_AUDIO,
        CODEC_ID_VORBIS,
        sizeof(vorbis_context),
        vorbis_decode_init,
        NULL,
        vorbis_decode_close,
        vorbis_decode_frame,
    };