Skip to content
Snippets Groups Projects
vorbis.c 60.9 KiB
Newer Older
  • Learn to ignore specific revisions
  •     if (vorbis_parse_id_hdr(vc)) {
            av_log(avccontext, AV_LOG_ERROR, "Id header corrupt.\n");
            vorbis_free(vc);
            return -1;
        }
    
    
        init_get_bits(gb, header_start[2], header_len[2]*8);
    
        hdr_type=get_bits(gb, 8);
        if (hdr_type!=5) {
            av_log(avccontext, AV_LOG_ERROR, "Third header is not the setup header.\n");
            return -1;
        }
        if (vorbis_parse_setup_hdr(vc)) {
            av_log(avccontext, AV_LOG_ERROR, "Setup header corrupt.\n");
            vorbis_free(vc);
            return -1;
        }
    
        avccontext->channels = vc->audio_channels;
        avccontext->sample_rate = vc->audio_samplerate;
    
        return 0 ;
    }
    
    // Decode audiopackets -------------------------------------------------
    
    
    // Read and decode floor
    
    static uint_fast8_t vorbis_floor0_decode(vorbis_context *vc,
                                             vorbis_floor_data *vfu, float *vec) {
        vorbis_floor0 * vf=&vfu->t0;
        float * lsp=vf->lsp;
        uint_fast32_t amplitude;
        uint_fast32_t book_idx;
    
        uint_fast8_t blockflag=vc->modes[vc->mode_number].blockflag;
    
    
        amplitude=get_bits(&vc->gb, vf->amplitude_bits);
        if (amplitude>0) {
            float last = 0;
            uint_fast16_t lsp_len = 0;
            uint_fast16_t idx;
            vorbis_codebook codebook;
    
            book_idx=get_bits(&vc->gb, ilog(vf->num_books));
            if ( book_idx >= vf->num_books ) {
                av_log( vc->avccontext, AV_LOG_ERROR,
                        "floor0 dec: booknumber too high!\n" );
                //FIXME: look above
            }
            AV_DEBUG( "floor0 dec: booknumber: %u\n", book_idx );
            codebook=vc->codebooks[vf->book_list[book_idx]];
    
            while (lsp_len<vf->order) {
                int vec_off;
    
                AV_DEBUG( "floor0 dec: book dimension: %d\n", codebook.dimensions );
                AV_DEBUG( "floor0 dec: maximum depth: %d\n", codebook.maxdepth );
                /* read temp vector */
                vec_off=get_vlc2(&vc->gb,
                                 codebook.vlc.table,
                                 codebook.nb_bits,
                                 codebook.maxdepth ) *
                                 codebook.dimensions;
                AV_DEBUG( "floor0 dec: vector offset: %d\n", vec_off );
                /* copy each vector component and add last to it */
                for (idx=0; idx<codebook.dimensions; ++idx) {
                    lsp[lsp_len+idx]=codebook.codevectors[vec_off+idx]+last;
                }
                last=lsp[lsp_len+idx-1]; /* set last to last vector component */
    
                lsp_len += codebook.dimensions;
            }
    #ifdef V_DEBUG
            /* DEBUG: output lsp coeffs */
            {
                int idx;
                for ( idx = 0; idx < lsp_len; ++idx )
                    AV_DEBUG("floor0 dec: coeff at %d is %f\n", idx, lsp[idx] );
            }
    #endif
    
            /* synthesize floor output vector */
            {
                int i;
                int order=vf->order;
                float wstep=M_PI/vf->bark_map_size;
    
                for(i=0;i<order;i++) { lsp[i]=2.0f*cos(lsp[i]); }
    
                AV_DEBUG("floor0 synth: map_size=%d; m=%d; wstep=%f\n",
                         vf->map_size, order, wstep);
    
                i=0;
    
                while(i<vf->map_size[blockflag]) {
                    int j, iter_cond=vf->map[blockflag][i];
    
                    float p=0.5f;
                    float q=0.5f;
                    float two_cos_w=2.0f*cos(wstep*iter_cond); // needed all times
    
                    /* similar part for the q and p products */
                    for(j=0;j<order;j+=2) {
                        q *= lsp[j]  -two_cos_w;
                        p *= lsp[j+1]-two_cos_w;
                    }
                    if(j==order) { // even order
                        p *= p*(2.0f-two_cos_w);
                        q *= q*(2.0f+two_cos_w);
                    }
                    else { // odd order
                        q *= two_cos_w-lsp[j]; // one more time for q
    
                        /* final step and square */
                        p *= p*(4.f-two_cos_w*two_cos_w);
                        q *= q;
                    }
    
                    /* calculate linear floor value */
                    {
                        q=exp( (
                                 ( (amplitude*vf->amplitude_offset)/
    
                                   (((1<<vf->amplitude_bits)-1) * sqrt(p+q)) )
    
                                 - vf->amplitude_offset ) * .11512925f
                             );
                    }
    
                    /* fill vector */
    
                    do { vec[i]=q; ++i; }while(vf->map[blockflag][i]==iter_cond);
    
                }
            }
        }
        else {
            /* this channel is unused */
            return 1;
        }
    
        AV_DEBUG(" Floor0 decoded\n");
    
        return 0;
    }
    static uint_fast8_t vorbis_floor1_decode(vorbis_context *vc, vorbis_floor_data *vfu, float *vec) {
        vorbis_floor1 * vf=&vfu->t1;
    
        GetBitContext *gb=&vc->gb;
        uint_fast16_t range_v[4]={ 256, 128, 86, 64 };
        uint_fast16_t range=range_v[vf->multiplier-1];
        uint_fast16_t floor1_Y[vf->x_list_dim];
        uint_fast16_t floor1_Y_final[vf->x_list_dim];
        uint_fast8_t floor1_flag[vf->x_list_dim];
        uint_fast8_t class_;
        uint_fast8_t cdim;
        uint_fast8_t cbits;
        uint_fast8_t csub;
        uint_fast8_t cval;
        int_fast16_t book;
        uint_fast16_t offset;
        uint_fast16_t i,j;
        uint_fast16_t *floor_x_sort=vf->x_list_order;
        /*u*/int_fast16_t adx, ady, off, predicted; // WTF ? dy/adx= (unsigned)dy/adx ?
        int_fast16_t dy, err;
        uint_fast16_t lx,hx, ly, hy=0;
    
    
        if (!get_bits1(gb)) return 1; // silence
    
    // Read values (or differences) for the floor's points
    
        floor1_Y[0]=get_bits(gb, ilog(range-1));
        floor1_Y[1]=get_bits(gb, ilog(range-1));
    
        AV_DEBUG("floor 0 Y %d floor 1 Y %d \n", floor1_Y[0], floor1_Y[1]);
    
        offset=2;
        for(i=0;i<vf->partitions;++i) {
            class_=vf->partition_class[i];
            cdim=vf->class_dimensions[class_];
            cbits=vf->class_subclasses[class_];
            csub=(1<<cbits)-1;
            cval=0;
    
            AV_DEBUG("Cbits %d \n", cbits);
    
            if (cbits) { // this reads all subclasses for this partition's class
                cval=get_vlc2(gb, vc->codebooks[vf->class_masterbook[class_]].vlc.table,
    
                vc->codebooks[vf->class_masterbook[class_]].nb_bits, 3);
    
            }
    
            for(j=0;j<cdim;++j) {
                book=vf->subclass_books[class_][cval & csub];
    
                AV_DEBUG("book %d Cbits %d cval %d  bits:%d \n", book, cbits, cval, get_bits_count(gb));
    
                cval=cval>>cbits;
                if (book>0) {
                    floor1_Y[offset+j]=get_vlc2(gb, vc->codebooks[book].vlc.table,
    
                    vc->codebooks[book].nb_bits, 3);
    
                } else {
                    floor1_Y[offset+j]=0;
                }
    
                AV_DEBUG(" floor(%d) = %d \n", vf->x_list[offset+j], floor1_Y[offset+j]);
            }
            offset+=cdim;
        }
    
    // Amplitude calculation from the differences
    
        floor1_flag[0]=1;
        floor1_flag[1]=1;
        floor1_Y_final[0]=floor1_Y[0];
        floor1_Y_final[1]=floor1_Y[1];
    
        for(i=2;i<vf->x_list_dim;++i) {
            uint_fast16_t val, highroom, lowroom, room;
            uint_fast16_t high_neigh_offs;
            uint_fast16_t low_neigh_offs;
    
            low_neigh_offs=vf->low_neighbour[i];
            high_neigh_offs=vf->high_neighbour[i];
            dy=floor1_Y_final[high_neigh_offs]-floor1_Y_final[low_neigh_offs];  // render_point begin
            adx=vf->x_list[high_neigh_offs]-vf->x_list[low_neigh_offs];
            ady= ABS(dy);
            err=ady*(vf->x_list[i]-vf->x_list[low_neigh_offs]);
    
            off=(int16_t)err/(int16_t)adx;
    
            if (dy<0) {
                predicted=floor1_Y_final[low_neigh_offs]-off;
            } else {
                predicted=floor1_Y_final[low_neigh_offs]+off;
            } // render_point end
    
            val=floor1_Y[i];
            highroom=range-predicted;
            lowroom=predicted;
            if (highroom < lowroom) {
                room=highroom*2;
            } else {
                room=lowroom*2;   // SPEC mispelling
            }
            if (val) {
                floor1_flag[low_neigh_offs]=1;
                floor1_flag[high_neigh_offs]=1;
                floor1_flag[i]=1;
                if (val>=room) {
                    if (highroom > lowroom) {
                        floor1_Y_final[i]=val-lowroom+predicted;
                    } else {
                        floor1_Y_final[i]=predicted-val+highroom-1;
                    }
                } else {
                    if (val & 1) {
                        floor1_Y_final[i]=predicted-(val+1)/2;
                    } else {
                        floor1_Y_final[i]=predicted+val/2;
                    }
                }
            } else {
                floor1_flag[i]=0;
                floor1_Y_final[i]=predicted;
            }
    
            AV_DEBUG(" Decoded floor(%d) = %d / val %d \n", vf->x_list[i], floor1_Y_final[i], val);
        }
    
    // Curve synth - connect the calculated dots and convert from dB scale FIXME optimize ?
    
        hx=0;
        lx=0;
        ly=floor1_Y_final[0]*vf->multiplier;  // conforms to SPEC
    
        vec[0]=floor1_inverse_db_table[ly];
    
        for(i=1;i<vf->x_list_dim;++i) {
            AV_DEBUG(" Looking at post %d \n", i);
    
            if (floor1_flag[floor_x_sort[i]]) {   // SPEC mispelled
                int_fast16_t x, y, dy, base, sy; // if uncommented: dy = -32 adx = 2  base = 2blablabla ?????
    
                hy=floor1_Y_final[floor_x_sort[i]]*vf->multiplier;
                hx=vf->x_list[floor_x_sort[i]];
    
                dy=hy-ly;
                adx=hx-lx;
                ady= (dy<0) ? -dy:dy;//ABS(dy);
    
                base=(int16_t)dy/(int16_t)adx;
    
    
                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,
    
                            vc->codebooks[vr->classbook].nb_bits, 3);
    
    Måns Rullgård's avatar
    Måns Rullgård committed
                            assert(vr->classifications > 1 && temp<=65536); //needed for inverse[]
    
                            for(i=0;i<c_p_c;++i) {
                                uint_fast32_t temp2;
    
    
                                temp2=(((uint_fast64_t)temp) * inverse[vr->classifications])>>32;
    
                                if (partition_count+c_p_c-1-i < ptns_to_read) {
                                    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;
    
                                uint_fast8_t dim= vc->codebooks[vqbook].dimensions;
                                uint_fast16_t step= dim==1 ? vr->partition_size
                                                  : FASTDIV(vr->partition_size, dim);
    
                                vorbis_codebook codebook= vc->codebooks[vqbook];
    
    
                                if (vr->type==0) {
    
                                    voffs=voffset+j*vlen;
                                    for(k=0;k<step;++k) {
    
                                        coffs=get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * codebook.dimensions;
    
                                        for(l=0;l<codebook.dimensions;++l) {
                                            vec[voffs+k+l*step]+=codebook.codevectors[coffs+l];  // FPMATH
    
                                        }
                                    }
                                }
                                else if (vr->type==1) {
                                    voffs=voffset+j*vlen;
    
                                    for(k=0;k<step;++k) {
    
                                        coffs=get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * codebook.dimensions;
    
                                        for(l=0;l<codebook.dimensions;++l, ++voffs) {
                                            vec[voffs]+=codebook.codevectors[coffs+l];  // FPMATH
    
                                            AV_DEBUG(" pass %d offs: %d curr: %f change: %f cv offs.: %d  \n", pass, voffs, vec[voffs], codebook.codevectors[coffs+l], coffs);
    
                                else if (vr->type==2 && ch==2 && (voffset&1)==0 && (codebook.dimensions&1)==0) { // most frequent case optimized
                                    voffs=voffset>>1;
    
                                    for(k=0;k<step;++k) {
    
                                        coffs=get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * codebook.dimensions;
    
                                        for(l=0;l<codebook.dimensions;l+=2, voffs++) {
                                            vec[voffs     ]+=codebook.codevectors[coffs+l  ];  // FPMATH
                                            vec[voffs+vlen]+=codebook.codevectors[coffs+l+1];  // 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], codebook.codevectors[coffs+l], coffs, l);
    
                                    for(k=0;k<step;++k) {
    
                                        coffs=get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * codebook.dimensions;
    
                                        for(l=0;l<codebook.dimensions;++l, ++voffs) {
                                            vec[voffs/ch+(voffs%ch)*vlen]+=codebook.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], codebook.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;
    
    void vorbis_inverse_coupling(float *mag, float *ang, int blocksize)
    {
        int i;
        for(i=0; i<blocksize; i++)
        {
            if (mag[i]>0.0) {
                if (ang[i]>0.0) {
                    ang[i]=mag[i]-ang[i];
                } else {
                    float temp=ang[i];
                    ang[i]=mag[i];
                    mag[i]+=temp;
                }
            } else {
                if (ang[i]>0.0) {
                    ang[i]+=mag[i];
                } else {
                    float temp=ang[i];
                    ang[i]=mag[i];
                    mag[i]-=temp;
                }
            }
        }
    }
    
    
    // Decode the audio packet using the functions above
    
    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 ?
    
    
    
        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]=floor->decode(vc, &floor->data, 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;
    
            vc->dsp.vorbis_inverse_coupling(mag, ang, blocksize/2);
    
        }
    
    // 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;
    
            vc->dsp.vector_fmul(ch_floor_ptr, ch_res_ptr, blocksize/2);
    
        }
    
    // 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;
    
    
            vc->mdct0.fft.imdct_calc(vc->modes[mode_number].blockflag ? &vc->mdct1 : &vc->mdct0, buf, ch_floor_ptr, buf_tmp);
    
            //FIXME process channels together, to allow faster simd vector_fmul_add_add?
    
            if (vc->modes[mode_number].blockflag) {
                // -- overlap/add
                if (previous_window) {
    
                    vc->dsp.vector_fmul_add_add(ret+j, buf, lwin, saved, vc->add_bias, vc->blocksize_1/2, step);
    
                    int len = (vc->blocksize_1-vc->blocksize_0)/4;
                    buf += len;
                    vc->dsp.vector_fmul_add_add(ret+j, buf, swin, saved, vc->add_bias, vc->blocksize_0/2, step);
                    k = vc->blocksize_0/2*step + j;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    buf += vc->blocksize_0/2;
    
                    if(vc->exp_bias){
                        for(i=0; i<len; i++, k+=step)
                            ((uint32_t*)ret)[k] = ((uint32_t*)buf)[i] + vc->exp_bias; // ret[k]=buf[i]*(1<<bias)
                    } else {
                        for(i=0; i<len; i++, k+=step)
                            ret[k] = buf[i] + fadd_bias;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    buf=vc->buf;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    buf += vc->blocksize_1/2;
    
                    vc->dsp.vector_fmul_reverse(saved, buf, lwin, vc->blocksize_1/2);
    
                    saved_start=0;
                } else {
                    saved_start=(vc->blocksize_1-vc->blocksize_0)/4;
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                    buf += vc->blocksize_1/2;
    
                    for(i=0; i<saved_start; i++)
                        ((uint32_t*)saved)[i] = ((uint32_t*)buf)[i] + vc->exp_bias;
                    vc->dsp.vector_fmul_reverse(saved+saved_start, buf+saved_start, swin, vc->blocksize_0/2);
    
                if(vc->add_bias) {
                    for(k=j, i=0;i<saved_start;++i, k+=step)
                        ret[k] = saved[i] + fadd_bias;
                } else {
                    for(k=j, i=0;i<saved_start;++i, k+=step)
                        ret[k] = saved[i];
    
                vc->dsp.vector_fmul_add_add(ret+k, buf, swin, saved+saved_start, vc->add_bias, vc->blocksize_0/2, step);
    
                retlen=saved_start+vc->blocksize_0/2;
                // -- save
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
                buf += vc->blocksize_0/2;
    
                vc->dsp.vector_fmul_reverse(saved, buf, swin, vc->blocksize_0/2);
    
                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);
    
    
        vc->dsp.float_to_int16(data, vc->ret, len);
    
        *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,
    };