// add the incoming page to the stream state; we decompose the page // into packet segments here as well. public int pagein(Page og) { byte[] header_base=og.header_base; int header=og.header; byte[] body_base=og.body_base; int body=og.body; int bodysize=og.body_len; int segptr=0; int version=og.version(); int continued=og.continued(); int bos=og.bos(); int eos=og.eos(); long granulepos=og.granulepos(); int _serialno=og.serialno(); int _pageno=og.pageno(); int segments=header_base[header+26]&0xff; // clean up 'returned data' { int lr=lacing_returned; int br=body_returned; // body data //System.out.println("br="+br+", body_fill="+body_fill); if(br!=0) { body_fill-=br; if(body_fill!=0) { Array.Copy(body_data, br, body_data, 0, body_fill); } body_returned=0; } //System.out.println("?? br="+br+", body_fill="+body_fill+" body_returned="+body_returned); if(lr!=0) { // segment table if((lacing_fill-lr)!=0) { Array.Copy(lacing_vals, lr, lacing_vals, 0, lacing_fill-lr); Array.Copy(granule_vals, lr, granule_vals, 0, lacing_fill-lr); } lacing_fill-=lr; lacing_packet-=lr; lacing_returned=0; } } // check the serial number if(_serialno!=serialno)return(-1); if(version>0)return(-1); lacing_expand(segments+1); // are we in sequence? if(_pageno!=pageno) { int i; // unroll previous partial packet (if any) for(i=lacing_packet;i<lacing_fill;i++) { body_fill-=lacing_vals[i]&0xff; //System.out.println("??"); } lacing_fill=lacing_packet; // make a note of dropped data in segment table if(pageno!=-1) { lacing_vals[lacing_fill++]=0x400; lacing_packet++; } // are we a 'continued packet' page? If so, we'll need to skip // some segments if(continued!=0) { bos=0; for(;segptr<segments;segptr++) { int val=(header_base[header+27+segptr]&0xff); body+=val; bodysize-=val; if(val<255) { segptr++; break; } } } } //System.out.println("bodysize="+bodysize); if(bodysize!=0) { body_expand(bodysize); Array.Copy(body_base, body, body_data, body_fill, bodysize); body_fill+=bodysize; } //System.out.println("bodyfill="+body_fill); { int saved=-1; while(segptr<segments) { int val=(header_base[header+27+segptr]&0xff); lacing_vals[lacing_fill]=val; granule_vals[lacing_fill]=-1; if(bos!=0) { lacing_vals[lacing_fill]|=0x100; bos=0; } if(val<255)saved=lacing_fill; lacing_fill++; segptr++; if(val<255)lacing_packet=lacing_fill; } /* set the granulepos on the last pcmval of the last full packet */ if(saved!=-1) { granule_vals[saved]=granulepos; } } if(eos!=0) { e_o_s=1; if(lacing_fill>0) lacing_vals[lacing_fill-1]|=0x200; } pageno=_pageno+1; return(0); }
// seek to a sample offset relative to the decompressed pcm stream // returns zero on success, nonzero on failure public int pcm_seek(long pos) { int link=-1; long total=pcm_total(-1); if(!skable)return(-1); // don't dump machine if we can't seek if(pos<0 || pos>total) { //goto seek_error; pcm_offset=-1; decode_clear(); return -1; } // which bitstream section does this pcm offset occur in? for(link=links-1;link>=0;link--) { total-=pcmlengths[link]; if(pos>=total)break; } // search within the logical bitstream for the page with the highest // pcm_pos preceeding (or equal to) pos. There is a danger here; // missing pages or incorrect frame number information in the // bitstream could make our task impossible. Account for that (it // would be an error condition) { long target=pos-total; long end=offsets[link+1]; long begin=offsets[link]; int best=(int)begin; Page og=new Page(); while(begin<end) { long bisect; int ret; if(end-begin<CHUNKSIZE) { bisect=begin; } else { bisect=(end+begin)/2; } seek_helper(bisect); ret=get_next_page(og,end-bisect); if(ret==-1) { end=bisect; } else { long granulepos=og.granulepos(); if(granulepos<target) { best=ret; // raw offset of packet with granulepos begin=offset; // raw offset of next packet } else { end=bisect; } } } // found our page. seek to it (call raw_seek). if(raw_seek(best)!=0) { //goto seek_error; pcm_offset=-1; decode_clear(); return -1; } } // verify result if(pcm_offset>=pos) { //goto seek_error; pcm_offset=-1; decode_clear(); return -1; } if(pos>pcm_total(-1)) { //goto seek_error; pcm_offset=-1; decode_clear(); return -1; } // discard samples until we reach the desired position. Crossing a // logical bitstream boundary with abandon is OK. while(pcm_offset<pos) { float[][] pcm; int target=(int)(pos-pcm_offset); float[][][] _pcm=new float[1][][]; int[] _index=new int[getInfo(-1).channels]; int samples=vd.synthesis_pcmout(_pcm, _index); pcm=_pcm[0]; if(samples>target)samples=target; vd.synthesis_read(samples); pcm_offset+=samples; if(samples<target) if(process_packet(1)==0) { pcm_offset=pcm_total(-1); // eof } } return 0; // seek_error: // dump machine so we're in a known state //pcm_offset=-1; //decode_clear(); //return -1; }
// last step of the OggVorbis_File initialization; get all the // vorbis_info structs and PCM positions. Only called by the seekable // initialization (local stream storage is hacked slightly; pay // attention to how that's done) public void prefetch_all_headers(Info first_i,Comment first_c, int dataoffset, VorbisFileInstance instance) { Page og=new Page(); int ret; vi=new Info[links]; vc=new Comment[links]; dataoffsets=new long[links]; pcmlengths=new long[links]; serialnos=new int[links]; for(int i=0;i<links;i++) { if(first_i!=null && first_c!=null && i==0) { // we already grabbed the initial header earlier. This just // saves the waste of grabbing it again // !!!!!!!!!!!!! vi[i]=first_i; //memcpy(vf->vi+i,first_i,sizeof(vorbis_info)); vc[i]=first_c; //memcpy(vf->vc+i,first_c,sizeof(vorbis_comment)); dataoffsets[i]=dataoffset; } else { // seek to the location of the initial header seek_helper(offsets[i], instance); //!!! if (fetch_headers(vi[i], vc[i], null, null, instance) == -1) { Console.Error.WriteLine("Error opening logical bitstream #"+(i+1)+"\n"); dataoffsets[i]=-1; } else { dataoffsets[i]=offset; instance.os.clear(); } } // get the serial number and PCM length of this link. To do this, // get the last page of the stream long end=offsets[i+1]; //!!! seek_helper(end, instance); while(true) { ret=get_prev_page(og, instance); if(ret==-1) { // this should not be possible Console.Error.WriteLine("Could not find last page of logical "+ "bitstream #"+(i)+"\n"); vi[i].clear(); vc[i].clear(); break; } if(og.granulepos()!=-1) { serialnos[i]=og.serialno(); pcmlengths[i]=og.granulepos(); break; } } } }
// add the incoming page to the stream state; we decompose the page // into packet segments here as well. public int pagein(Page og) { byte[] header_base = og.header_base; int header = og.header; byte[] body_base = og.body_base; int body = og.body; int bodysize = og.body_len; int segptr = 0; int version = og.version(); int continued = og.continued(); int bos = og.bos(); int eos = og.eos(); long granulepos = og.granulepos(); int _serialno = og.serialno(); int _pageno = og.pageno(); int segments = header_base[header + 26] & 0xff; // clean up 'returned data' { int lr = lacing_returned; int br = body_returned; // body data //System.out.println("br="+br+", body_fill="+body_fill); if (br != 0) { body_fill -= br; if (body_fill != 0) { Array.Copy(body_data, br, body_data, 0, body_fill); } body_returned = 0; } //System.out.println("?? br="+br+", body_fill="+body_fill+" body_returned="+body_returned); if (lr != 0) { // segment table if ((lacing_fill - lr) != 0) { Array.Copy(lacing_vals, lr, lacing_vals, 0, lacing_fill - lr); Array.Copy(granule_vals, lr, granule_vals, 0, lacing_fill - lr); } lacing_fill -= lr; lacing_packet -= lr; lacing_returned = 0; } } // check the serial number if (_serialno != serialno) { return(-1); } if (version > 0) { return(-1); } lacing_expand(segments + 1); // are we in sequence? if (_pageno != pageno) { int i; // unroll previous partial packet (if any) for (i = lacing_packet; i < lacing_fill; i++) { body_fill -= lacing_vals[i] & 0xff; //System.out.println("??"); } lacing_fill = lacing_packet; // make a note of dropped data in segment table if (pageno != -1) { lacing_vals[lacing_fill++] = 0x400; lacing_packet++; } // are we a 'continued packet' page? If so, we'll need to skip // some segments if (continued != 0) { bos = 0; for (; segptr < segments; segptr++) { int val = (header_base[header + 27 + segptr] & 0xff); body += val; bodysize -= val; if (val < 255) { segptr++; break; } } } } //System.out.println("bodysize="+bodysize); if (bodysize != 0) { body_expand(bodysize); Array.Copy(body_base, body, body_data, body_fill, bodysize); body_fill += bodysize; } //System.out.println("bodyfill="+body_fill); { int saved = -1; while (segptr < segments) { int val = (header_base[header + 27 + segptr] & 0xff); lacing_vals[lacing_fill] = val; granule_vals[lacing_fill] = -1; if (bos != 0) { lacing_vals[lacing_fill] |= 0x100; bos = 0; } if (val < 255) { saved = lacing_fill; } lacing_fill++; segptr++; if (val < 255) { lacing_packet = lacing_fill; } } /* set the granulepos on the last pcmval of the last full packet */ if (saved != -1) { granule_vals[saved] = granulepos; } } if (eos != 0) { e_o_s = 1; if (lacing_fill > 0) { lacing_vals[lacing_fill - 1] |= 0x200; } } pageno = _pageno + 1; return(0); }