]> Joshua Wise's Git repositories - patchfork.git/blob - jorbis/src/com/jcraft/jorbis/VorbisFile.java.new
initial import from pitchfork-0.5.5
[patchfork.git] / jorbis / src / com / jcraft / jorbis / VorbisFile.java.new
1 /* JOrbis
2  * Copyright (C) 2000 ymnk, JCraft,Inc.
3  *  
4  * Written by: 2000 ymnk<ymnk@jcraft.com>
5  *   
6  * Many thanks to 
7  *   Monty <monty@xiph.org> and 
8  *   The XIPHOPHORUS Company http://www.xiph.org/ .
9  * JOrbis has been based on their awesome works, Vorbis codec.
10  *   
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public License
13  * as published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15    
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Library General Public License for more details.
20  * 
21  * You should have received a copy of the GNU Library General Public
22  * License along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 package com.jcraft.jorbis;
27
28 import com.jcraft.jogg.*;
29 import java.io.InputStream;
30
31 public class VorbisFile{
32   static final int CHUNKSIZE=4096;
33   static final int SEEK_SET=0;
34
35   InputStream datasource;
36   boolean seekable=false;
37   long offset;
38   long end;
39   
40   SyncState oy=new SyncState();
41
42   int links;
43   Comment[] vc;
44   Info[] vi;
45
46   long[] offsets;
47   long[] dataoffsets;
48   int[] serialnos;
49   long[] pcmlengths;
50
51
52
53   // Decoding working state local storage
54   long pcm_offset;
55   boolean decode_ready=false;
56   int current_serialno;
57   int current_link;
58
59   float bittrack;
60   float samptrack;
61
62   StreamState os=new StreamState(); // take physical pages, weld into a logical
63                                     // stream of packets
64   DspState vd=new DspState(); // central working state for 
65                               // the packet->PCM decoder
66   Block vb=new Block(vd);     // local working space for packet->PCM decode
67
68   //ov_callbacks callbacks;
69
70   public VorbisFile(String file) throws JOrbisException {
71     super();
72     InputStream is=null;
73     try{ is=new java.io.BufferedInputStream(new java.io.FileInputStream(file));}
74     catch(Exception e){
75       throw new JOrbisException("VorbisFile: "+e.toString());
76     }
77     int ret=open(is, null, 0);
78     if(ret==-1){
79       throw new JOrbisException("VorbisFile: open return -1");
80     }
81   }
82
83   public VorbisFile(InputStream is, byte[] initial, int ibytes)
84     throws JOrbisException {
85     super();
86     int ret=open(is, initial, ibytes);
87     if(ret==-1){
88     }
89   }
90
91   private int get_data(){
92     int index=oy.buffer(CHUNKSIZE);
93     byte[] buffer=oy.data;
94 //  int bytes=callbacks.read_func(buffer, index, 1, CHUNKSIZE, datasource);
95     int bytes=0;
96     try{
97       bytes=datasource.read(buffer, index, CHUNKSIZE);
98     }
99     catch(Exception e){System.err.println(e);}
100     oy.wrote(bytes);
101     return bytes;
102   }
103
104   private void seek_helper(int offst){
105     //callbacks.seek_func(datasource, offst, SEEK_SET);
106     fseek64_wrap(datasource, offst, SEEK_SET);
107     this.offset=offst;
108     oy.reset();
109   }
110
111   private int get_next_page(Page page, int boundary){
112     if(boundary>0) boundary+=offset;
113     while(true){
114       int more;
115       if(boundary>0 && offset>=boundary)return -1;
116       more=oy.pageseek(page);
117       if(more<0){offset-=more;}
118       else{
119         if(more==0){
120           if(boundary==0)return -1;
121           if(get_data()<=0)return -1;
122         }
123         else{
124           int ret=(int)offset; //!!!
125           offset+=more;
126           return ret;
127         }
128       }
129     }
130   }
131
132   private int get_prev_page(Page page){
133     int begin=(int)offset; //!!!
134     int ret;
135     int offst=-1;
136     while(offst==-1){
137       begin-=CHUNKSIZE;
138       seek_helper(begin);
139       while(offset<begin+CHUNKSIZE){
140         ret=get_next_page(page, begin+CHUNKSIZE-((int)offset));
141         if(ret==-1){ break; }
142         else{ offst=ret; }
143       }
144     }
145     seek_helper((int)offset); //!!!
146     ret=get_next_page(page, CHUNKSIZE);
147     if(ret==-1){
148       System.err.println("Missed page fencepost at end of logical bitstream Exiting");
149       System.exit(1);
150     }
151     return offst;
152   }
153
154   void bisect_forward_serialno(int begin, int searched, int end, int currentno, int m){
155     int endsearched=end;
156     int next=end;
157     Page page=new Page();
158     int ret;
159     while(searched<endsearched){
160       int bisect;
161       if(endsearched-searched<CHUNKSIZE){
162         bisect=searched;
163       }
164       else{
165         bisect=(searched+endsearched)/2;
166       }
167
168       seek_helper(bisect);
169       ret=get_next_page(page, -1);
170       if(ret<0 || page.serialno()!=currentno){
171         endsearched=bisect;
172         if(ret>=0)next=ret;
173       }
174       else{
175         searched=ret+page.header_len+page.body_len;
176       }
177     }
178     seek_helper(next);
179     ret=get_next_page(page, -1);
180
181     if(searched>=end || ret==-1){
182       links=m+1;
183       offsets=new long[m+2];
184       offsets[m+1]=searched;
185     }
186     else{
187       bisect_forward_serialno(next, (int)offset, end, page.serialno(), m+1);
188     }
189     offsets[m]=begin;
190   }
191
192   // uses the local ogg_stream storage in vf; this is important for
193   // non-streaming input sources
194   int fetch_headers(Info vi, Comment vc, int[] serialno){
195     //System.err.println("fetch_headers");
196     Page og=new Page();
197     Packet op=new Packet();
198     int ret;
199
200     ret=get_next_page(og, CHUNKSIZE);
201     if(ret==-1){
202       System.err.println("Did not find initial header for bitstream.");
203       return -1;
204     }
205   
206     if(serialno!=null)serialno[0]=og.serialno();
207
208     os.init(og.serialno());
209   
210     // extract the initial header from the first page and verify that the
211     // Ogg bitstream is in fact Vorbis data
212   
213     vi.init();
214     vc.init();
215   
216     int i=0;
217     while(i<3){
218       os.pagein(og);
219       while(i<3){
220         int result=os.packetout(op);
221         if(result==0)break;
222         if(result==-1){
223           System.err.println("Corrupt header in logical bitstream.");
224           //goto bail_header;
225           vi.clear();
226           vc.clear();
227           os.clear();
228            return -1;
229         }
230         if(vi.synthesis_headerin(vc, op)!=0){
231           System.err.println("Illegal header in logical bitstream.");
232           //goto bail_header;
233           vi.clear();
234           vc.clear();
235           os.clear();
236           return -1;
237         }
238         i++;
239       }
240       if(i<3)
241         if(get_next_page(og, 1)<0){
242           System.err.println("Missing header in logical bitstream.");
243           //goto bail_header;
244           vi.clear();
245           vc.clear();
246           os.clear();
247           return -1;
248         }
249     }
250     return 0; 
251
252 //  bail_header:
253 //    vorbis_info_clear(vi);
254 //    vorbis_comment_clear(vc);
255 //    ogg_stream_clear(&vf->os);
256 //    return -1;
257   }
258
259   // last step of the OggVorbis_File initialization; get all the
260   // vorbis_info structs and PCM positions.  Only called by the seekable
261   // initialization (local stream storage is hacked slightly; pay
262   // attention to how that's done)
263   void prefetch_all_headers(Info first_i,Comment first_c, int dataoffset){
264     Page og=new Page();
265     int ret;
266   
267     vi=new Info[links];
268     vc=new Comment[links];
269     dataoffsets=new long[links];
270     pcmlengths=new long[links];
271     serialnos=new int[links];
272   
273     for(int i=0;i<links;i++){
274       if(first_i!=null && first_c!=null && i==0){
275         // we already grabbed the initial header earlier.  This just
276         // saves the waste of grabbing it again
277         // !!!!!!!!!!!!!
278         vi[i]=first_i;
279         //memcpy(vf->vi+i,first_i,sizeof(vorbis_info));
280         vc[i]=first_c;
281         //memcpy(vf->vc+i,first_c,sizeof(vorbis_comment));
282         dataoffsets[i]=dataoffset;
283       }
284       else{
285         // seek to the location of the initial header
286         seek_helper((int)offsets[i]); //!!!
287         if(fetch_headers(vi[i], vc[i], null)==-1){
288           System.err.println("Error opening logical bitstream #"+(i+1)+"\n");
289           dataoffsets[i]=-1;
290         }
291         else{
292           dataoffsets[i]=offset;
293           os.clear();
294         }
295       }
296
297       // get the serial number and PCM length of this link. To do this,
298       // get the last page of the stream
299       {
300         int end=(int)offsets[i+1]; //!!!
301         seek_helper(end);
302
303         while(true){
304           ret=get_prev_page(og);
305           if(ret==-1){
306             // this should not be possible
307             System.err.println("Could not find last page of logical "+
308                                "bitstream #"+(i)+"\n");
309             vi[i].clear();
310             vc[i].clear();
311             break;
312           }
313           if(og.granulepos()!=-1){
314             serialnos[i]=og.serialno();
315             pcmlengths[i]=og.granulepos();
316             break;
317           }
318         }
319       }
320     }
321   }
322
323   int make_decode_ready(){
324     if(decode_ready)System.exit(1);
325     vd.synthesis_init(vi[0]);
326     vb.init(vd);
327     decode_ready=true;
328     return(0);
329   }
330
331   int open_seekable(){
332     Info initial_i=new Info();
333     Comment initial_c=new Comment();
334     int serialno,end;
335     int ret;
336     int dataoffset;
337     Page og=new Page();
338 System.out.println("open_seekable");  
339     // is this even vorbis...?
340     int[] foo=new int[1];
341     ret=fetch_headers(initial_i, initial_c, foo);
342     serialno=foo[0];
343     dataoffset=(int)offset; //!!
344     os.clear();
345     if(ret==-1)return(-1);
346   
347     // we can seek, so set out learning all about this file
348     seekable=true;
349     //(callbacks.seek_func)(datasource, 0, SEEK_END);
350     fseek64_wrap(datasource, (int)offset, SEEK_SET);
351     //offset=end=(callbacks.tell_func)(datasource);
352     end=(int)offset;
353   
354     // We get the offset for the last page of the physical bitstream.
355     // Most OggVorbis files will contain a single logical bitstream
356     end=get_prev_page(og);
357
358     // moer than one logical bitstream?
359     if(og.serialno()!=serialno){
360       // Chained bitstream. Bisect-search each logical bitstream
361       // section.  Do so based on serial number only
362       bisect_forward_serialno(0,0,end+1,serialno,0);
363     }
364     else{
365       // Only one logical bitstream
366       bisect_forward_serialno(0,end,end+1,serialno,0);
367     }
368     prefetch_all_headers(initial_i, initial_c, dataoffset);
369
370 System.out.println("?");  
371     return(raw_seek(0));
372   }
373
374   int open_nonseekable(){
375     //System.err.println("open_nonseekable");
376     // we cannot seek. Set up a 'single' (current) logical bitstream entry
377     links=1;
378     vi=new Info[links]; vi[0]=new Info(); // ??
379     vc=new Comment[links]; vc[0]=new Comment(); // ?? bug?
380
381     // Try to fetch the headers, maintaining all the storage
382     int[]foo=new int[1];
383     if(fetch_headers(vi[0], vc[0], foo)==-1)return(-1);
384     current_serialno=foo[0];
385     make_decode_ready();
386     return 0;
387   }
388
389   // clear out the current logical bitstream decoder
390   void decode_clear(){
391     os.clear();
392     vd.clear();
393     vb.clear();
394     decode_ready=false;
395     bittrack=0.f;
396     samptrack=0.f;
397   }
398
399   // fetch and process a packet.  Handles the case where we're at a
400   // bitstream boundary and dumps the decoding machine.  If the decoding
401   // machine is unloaded, it loads it.  It also keeps pcm_offset up to
402   // date (seek and read both use this.  seek uses a special hack with
403   // readp). 
404   //
405   // return: -1) hole in the data (lost packet) 
406   //          0) need more date (only if readp==0)/eof
407   //          1) got a packet 
408
409   int process_packet(int readp){
410 System.out.println("porcess_packet:"+ readp+" , decode_ready="+decode_ready);
411     Page og=new Page();
412
413     // handle one packet.  Try to fetch it from current stream state
414     // extract packets from page
415     while(true){
416       // process a packet if we can.  If the machine isn't loaded,
417       // neither is a page
418       if(decode_ready){
419         Packet op=new Packet();
420         int result=os.packetout(op);
421         long granulepos;
422         // if(result==-1)return(-1); // hole in the data. For now, swallow
423                                      // and go. We'll need to add a real
424                                      // error code in a bit.
425         if(result>0){
426           // got a packet.  process it
427           granulepos=op.granulepos;
428           if(vb.synthesis(op)==0){ // lazy check for lazy
429                                    // header handling.  The
430                                    // header packets aren't
431                                    // audio, so if/when we
432                                    // submit them,
433                                    // vorbis_synthesis will
434                                    // reject them
435             // suck in the synthesis data and track bitrate
436             {
437               int oldsamples=vd.synthesis_pcmout(null, null);
438               vd.synthesis_blockin(vb);
439               samptrack+=vd.synthesis_pcmout(null, null)-oldsamples;
440               bittrack+=op.bytes*8;
441             }
442           
443             // update the pcm offset.
444             if(granulepos!=-1 && op.e_o_s==0){
445               int link=(seekable?current_link:0);
446               int samples;
447               // this packet has a pcm_offset on it (the last packet
448               // completed on a page carries the offset) After processing
449               // (above), we know the pcm position of the *last* sample
450               // ready to be returned. Find the offset of the *first*
451               // 
452               // As an aside, this trick is inaccurate if we begin
453               // reading anew right at the last page; the end-of-stream
454               // granulepos declares the last frame in the stream, and the
455               // last packet of the last page may be a partial frame.
456               // So, we need a previous granulepos from an in-sequence page
457               // to have a reference point.  Thus the !op.e_o_s clause above
458             
459               samples=vd.synthesis_pcmout(null, null);
460               granulepos-=samples;
461               for(int i=0;i<link;i++){
462                 granulepos+=pcmlengths[i];
463               }
464               pcm_offset=granulepos;
465             }
466             return(1);
467           }
468         }
469       }
470
471       if(readp==0)return(0);
472       if(get_next_page(og,-1)<0)return(0); // eof. leave unitialized
473
474       // bitrate tracking; add the header's bytes here, the body bytes
475       // are done by packet above
476       bittrack+=og.header_len*8;
477
478       // has our decoding just traversed a bitstream boundary?
479       if(decode_ready){
480         if(current_serialno!=og.serialno()){
481           decode_clear();
482         }
483       }
484
485       // Do we need to load a new machine before submitting the page?
486       // This is different in the seekable and non-seekable cases.  
487       // 
488       // In the seekable case, we already have all the header
489       // information loaded and cached; we just initialize the machine
490       // with it and continue on our merry way.
491       // 
492       // In the non-seekable (streaming) case, we'll only be at a
493       // boundary if we just left the previous logical bitstream and
494       // we're now nominally at the header of the next bitstream
495
496       if(!decode_ready){
497         int i;
498         if(seekable){
499           current_serialno=og.serialno();
500         
501           // match the serialno to bitstream section.  We use this rather than
502           // offset positions to avoid problems near logical bitstream
503           // boundaries
504           for(i=0;i<links;i++){
505             if(serialnos[i]==current_serialno)break;
506           }
507           if(i==links)return(-1); // sign of a bogus stream.  error out,
508                                   // leave machine uninitialized
509           current_link=i;
510
511           os.init(current_serialno);
512           os.reset(); 
513
514         }
515         else{
516           // we're streaming
517           // fetch the three header packets, build the info struct
518           int foo[]=new int[1];
519           fetch_headers(vi[0], vc[0], foo);
520           current_serialno=foo[0];
521           current_link++;
522           i=0;
523         }
524         make_decode_ready();
525       }
526       os.pagein(og);
527     }
528   }
529
530   //The helpers are over; it's all toplevel interface from here on out
531   // clear out the OggVorbis_File struct
532   int clear(){
533     vb.clear();
534     vd.clear();
535     os.clear();
536     
537     if(vi!=null && links!=0){
538       for(int i=0;i<links;i++){
539         vi[i].clear();
540         vc[i].clear();
541       }
542       vi=null;
543       vc=null;
544     }
545     if(dataoffsets!=null)dataoffsets=null;
546     if(pcmlengths!=null)pcmlengths=null;
547     if(serialnos!=null)serialnos=null;
548     if(offsets!=null)offsets=null;
549     oy.clear();
550     //if(datasource!=null)(vf->callbacks.close_func)(vf->datasource);
551     //memset(vf,0,sizeof(OggVorbis_File));
552     return(0);
553   }
554
555   static int fseek64_wrap(InputStream fis,
556                           //int64_t off,
557                           int off,
558                           int whence){
559
560     if(!fis.markSupported()){ return -1; }
561     try{
562       try{if(whence==0){ fis.reset(); }}
563       catch(Exception ee){System.out.println(ee);}
564       fis.skip(off);
565     }
566     catch(Exception e){ System.out.println(e);
567     //return -1;
568     }
569     return 0;
570   }
571
572   // inspects the OggVorbis file and finds/documents all the logical
573   // bitstreams contained in it.  Tries to be tolerant of logical
574   // bitstream sections that are truncated/woogie. 
575   //
576   // return: -1) error
577   //          0) OK
578
579   int open(InputStream is, byte[] initial, int ibytes){
580     return open_callbacks(is, initial, ibytes//, callbacks
581                              );
582   }
583
584   int open_callbacks(InputStream is, byte[] initial, 
585                         int ibytes//, callbacks callbacks
586                         ){
587 //  int offset=callbacks.seek_func(f,0,SEEK_CUR);
588     int _offset=fseek64_wrap(is, (int)offset, SEEK_SET);
589     int ret;
590     // memset(vf,0,sizeof(OggVorbis_File));
591     datasource=is;
592     //callbacks = _callbacks;
593
594     // init the framing state
595     oy.init();
596
597     // perhaps some data was previously read into a buffer for testing
598     // against other stream types.  Allow initialization from this
599     // previously read data (as we may be reading from a non-seekable
600     // stream)
601     if(initial!=null){
602       int index=oy.buffer(ibytes);
603       System.arraycopy(initial, 0, oy.data, index, ibytes);
604       oy.wrote(ibytes);
605     }
606
607 System.out.println("open_callbacks="+_offset);
608     // can we seek? Stevens suggests the seek test was portable
609     if(_offset!=-1){ ret=open_seekable(); }
610     else{ ret=open_nonseekable(); }
611
612 System.out.println("ret="+ret);
613
614     if(ret!=0){
615       datasource=null;
616       clear();
617     }
618
619     return(ret);
620   }
621
622   // How many logical bitstreams in this physical bitstream?
623   public int streams(){
624     return links;
625   }
626
627   // Is the FILE * associated with vf seekable?
628   public boolean seekable(){
629     return seekable;
630   }
631
632   // returns the bitrate for a given logical bitstream or the entire
633   // physical bitstream.  If the file is open for random access, it will
634   // find the *actual* average bitrate.  If the file is streaming, it
635   // returns the nominal bitrate (if set) else the average of the
636   // upper/lower bounds (if set) else -1 (unset).
637   // 
638   // If you want the actual bitrate field settings, get them from the
639   // vorbis_info structs
640
641   public int bitrate(int i){
642     if(i>=links)return(-1);
643     if(!seekable && i!=0)return(bitrate(0));
644     if(i<0){
645       long bits=0;
646       for(int j=0;j<links;j++){
647         bits+=(offsets[j+1]-dataoffsets[j])*8;
648       }
649       return((int)Math.rint(bits/time_total(-1)));
650     }
651     else{
652       if(seekable){
653         // return the actual bitrate
654         return((int)Math.rint((offsets[i+1]-dataoffsets[i])*8/time_total(i)));
655       }
656       else{
657         // return nominal if set
658         if(vi[i].bitrate_nominal>0){
659           return vi[i].bitrate_nominal;
660         }
661         else{
662           if(vi[i].bitrate_upper>0){
663             if(vi[i].bitrate_lower>0){
664               return (vi[i].bitrate_upper+vi[i].bitrate_lower)/2;
665             }else{
666               return vi[i].bitrate_upper;
667             }
668           }
669           return(-1);
670         }
671       }
672     }
673   }
674
675   // returns the actual bitrate since last call.  returns -1 if no
676   // additional data to offer since last call (or at beginning of stream)
677   public int bitrate_instant(){
678     int _link=(seekable?current_link:0);
679     if(samptrack==0)return(-1);
680     int ret=(int)(bittrack/samptrack*vi[_link].rate+.5);
681     bittrack=0.f;
682     samptrack=0.f;
683     return(ret);
684   }
685
686   public int serialnumber(int i){
687     if(i>=links)return(-1);
688     if(!seekable && i>=0)return(serialnumber(-1));
689     if(i<0){
690       return(current_serialno);
691     }
692     else{
693       return(serialnos[i]);
694     }
695   }
696
697   // returns: total raw (compressed) length of content if i==-1
698   //          raw (compressed) length of that logical bitstream for i==0 to n
699   //          -1 if the stream is not seekable (we can't know the length)
700
701   public long raw_total(int i){
702 System.out.println("raw_total: "+seekable);
703     if(!seekable || i>=links)return(-1);
704     if(i<0){
705       long acc=0;               // bug?
706       for(int j=0;j<links;j++){
707         acc+=raw_total(j);
708       }
709       return(acc);
710     }
711     else{
712       return(offsets[i+1]-offsets[i]);
713     }
714   }
715
716   // returns: total PCM length (samples) of content if i==-1
717   //          PCM length (samples) of that logical bitstream for i==0 to n
718   //          -1 if the stream is not seekable (we can't know the length)
719   public long pcm_total(int i){
720     if(!seekable || i>=links)return(-1);
721     if(i<0){
722       long acc=0;
723       for(int j=0;j<links;j++){
724         acc+=pcm_total(j);
725       }
726       return(acc);
727     }
728     else{
729       return(pcmlengths[i]);
730     }
731   }
732
733   // returns: total seconds of content if i==-1
734   //          seconds in that logical bitstream for i==0 to n
735   //          -1 if the stream is not seekable (we can't know the length)
736   public float time_total(int i){
737     if(!seekable || i>=links)return(-1);
738     if(i<0){
739       float acc=0;
740       for(int j=0;j<links;j++){
741         acc+=time_total(j);
742       }
743       return(acc);
744     }
745     else{
746       return((float)(pcmlengths[i])/vi[i].rate);
747     }
748   }
749
750   // seek to an offset relative to the *compressed* data. This also
751   // immediately sucks in and decodes pages to update the PCM cursor. It
752   // will cross a logical bitstream boundary, but only if it can't get
753   // any packets out of the tail of the bitstream we seek to (so no
754   // surprises). 
755   // 
756   // returns zero on success, nonzero on failure
757
758   public int raw_seek(int pos){
759 System.out.println("raw_seek: "+pos);
760     if(!seekable)return(-1); // don't dump machine if we can't seek
761     if(pos<0 || pos>offsets[links]){
762       //goto seek_error;
763       pcm_offset=-1;
764       decode_clear();
765       return -1;
766     }
767 System.out.println("#1");
768     // clear out decoding machine state
769     pcm_offset=-1;
770 System.out.println("#2");
771     decode_clear();
772 System.out.println("#3");
773     // seek
774     seek_helper(pos);
775
776     // we need to make sure the pcm_offset is set.  We use the
777     // _fetch_packet helper to process one packet with readp set, then
778     // call it until it returns '0' with readp not set (the last packet
779     // from a page has the 'granulepos' field set, and that's how the
780     // helper updates the offset
781 System.out.println("#4");
782     switch(process_packet(1)){
783     case 0:
784 System.out.println("?0");
785       // oh, eof. There are no packets remaining.  Set the pcm offset to
786       // the end of file
787       pcm_offset=pcm_total(-1);
788       return(0);
789     case -1:
790 System.out.println("?-1");
791       // error! missing data or invalid bitstream structure
792       //goto seek_error;
793       pcm_offset=-1;
794       decode_clear();
795       return -1;
796     default:
797 System.out.println("?break");
798       // all OK
799       break;
800     }
801 System.out.println("pcm_offset="+pcm_offset);
802     while(true){
803       switch(process_packet(0)){
804       case 0:
805         // the offset is set.  If it's a bogus bitstream with no offset
806         // information, it's not but that's not our fault.  We still run
807         // gracefully, we're just missing the offset
808         return(0);
809       case -1:
810         // error! missing data or invalid bitstream structure
811         //goto seek_error;
812         pcm_offset=-1;
813         decode_clear();
814         return -1;
815       default:
816         // continue processing packets
817         break;
818       }
819     }
820   
821   // seek_error:
822     // dump the machine so we're in a known state
823     //pcm_offset=-1;
824     //decode_clear();
825     //return -1;
826   }
827
828   // seek to a sample offset relative to the decompressed pcm stream 
829   // returns zero on success, nonzero on failure
830
831   public int pcm_seek(long pos){
832     int link=-1;
833     long total=pcm_total(-1);
834
835     if(!seekable)return(-1); // don't dump machine if we can't seek
836     if(pos<0 || pos>total){
837       //goto seek_error;
838       pcm_offset=-1;
839       decode_clear();
840       return -1;
841     }
842
843     // which bitstream section does this pcm offset occur in?
844     for(link=links-1;link>=0;link--){
845       total-=pcmlengths[link];
846       if(pos>=total)break;
847     }
848
849     // search within the logical bitstream for the page with the highest
850     // pcm_pos preceeding (or equal to) pos.  There is a danger here;
851     // missing pages or incorrect frame number information in the
852     // bitstream could make our task impossible.  Account for that (it
853     // would be an error condition)
854     {
855       long target=pos-total;
856       int end=(int)offsets[link+1];
857       int begin=(int)offsets[link];
858       int best=begin;
859
860       Page og=new Page();
861       while(begin<end){
862         int bisect;
863         int ret;
864     
865         if(end-begin<CHUNKSIZE){
866           bisect=begin;
867         }
868         else{
869           bisect=(end+begin)/2;
870         }
871     
872         seek_helper(bisect);
873         ret=get_next_page(og,end-bisect);
874       
875         if(ret==-1){
876           end=bisect;
877         }
878         else{
879           long granulepos=og.granulepos();
880           if(granulepos<target){
881             best=ret;  // raw offset of packet with granulepos
882             begin=(int)offset; // raw offset of next packet
883           }
884           else{
885             end=bisect;
886           }
887         }
888       }
889       // found our page. seek to it (call raw_seek).
890       if(raw_seek(best)!=0){
891         //goto seek_error;
892         pcm_offset=-1;
893         decode_clear();
894         return -1;
895       }
896     }
897
898     // verify result
899     if(pcm_offset>=pos){
900       //goto seek_error;
901       pcm_offset=-1;
902       decode_clear();
903       return -1;
904     }
905     if(pos>pcm_total(-1)){
906       //goto seek_error;
907       pcm_offset=-1;
908       decode_clear();
909       return -1;
910     }
911
912     // discard samples until we reach the desired position. Crossing a
913     // logical bitstream boundary with abandon is OK.
914     while(pcm_offset<pos){
915       float[][] pcm;
916       int target=(int)(pos-pcm_offset);
917       float[][][] _pcm=new float[1][][];
918       int[] _index=new int[info(-1).channels];
919       int samples=vd.synthesis_pcmout(_pcm, _index);
920       pcm=_pcm[0];
921
922       if(samples>target)samples=target;
923       vd.synthesis_read(samples);
924       pcm_offset+=samples;
925     
926       if(samples<target)
927         if(process_packet(1)==0){
928           pcm_offset=pcm_total(-1); // eof
929         }
930     }
931     return 0;
932   
933   // seek_error:
934     // dump machine so we're in a known state
935     //pcm_offset=-1;
936     //decode_clear();
937     //return -1;
938   }
939
940   // seek to a playback time relative to the decompressed pcm stream 
941   // returns zero on success, nonzero on failure
942   public int time_seek(float seconds){
943     // translate time to PCM position and call pcm_seek
944
945     int link=-1;
946     long pcm_total=pcm_total(-1);
947     float time_total=time_total(-1);
948
949     if(!seekable)return(-1); // don't dump machine if we can't seek
950     if(seconds<0 || seconds>time_total){
951       //goto seek_error;
952       pcm_offset=-1;
953       decode_clear();
954       return -1;
955     }
956   
957     // which bitstream section does this time offset occur in?
958     for(link=links-1;link>=0;link--){
959       pcm_total-=pcmlengths[link];
960       time_total-=time_total(link);
961       if(seconds>=time_total)break;
962     }
963
964     // enough information to convert time offset to pcm offset
965     {
966       long target=(long)(pcm_total+(seconds-time_total)*vi[link].rate);
967       return(pcm_seek(target));
968     }
969
970   //seek_error:
971     // dump machine so we're in a known state
972     //pcm_offset=-1;
973     //decode_clear();
974     //return -1;
975   }
976
977   // tell the current stream offset cursor.  Note that seek followed by
978   // tell will likely not give the set offset due to caching
979   public long raw_tell(){
980     return(offset);
981   }
982
983   // return PCM offset (sample) of next PCM sample to be read
984   public long pcm_tell(){
985     return(pcm_offset);
986   }
987
988   // return time offset (seconds) of next PCM sample to be read
989   public float time_tell(){
990     // translate time to PCM position and call pcm_seek
991
992     int link=-1;
993     long pcm_total=0;
994     float time_total=0.f;
995   
996     if(seekable){
997       pcm_total=pcm_total(-1);
998       time_total=time_total(-1);
999   
1000       // which bitstream section does this time offset occur in?
1001       for(link=links-1;link>=0;link--){
1002         pcm_total-=pcmlengths[link];
1003         time_total-=time_total(link);
1004         if(pcm_offset>=pcm_total)break;
1005       }
1006     }
1007
1008     return((float)time_total+(float)(pcm_offset-pcm_total)/vi[link].rate);
1009   }
1010
1011   //  link:   -1) return the vorbis_info struct for the bitstream section
1012   //              currently being decoded
1013   //         0-n) to request information for a specific bitstream section
1014   //
1015   // In the case of a non-seekable bitstream, any call returns the
1016   // current bitstream.  NULL in the case that the machine is not
1017   // initialized
1018
1019   public Info info(int link){
1020     if(seekable){
1021       if(link<0){
1022         if(decode_ready){
1023           return vi[current_link];
1024         }
1025         else{
1026           return null;
1027         }
1028       }
1029       else{
1030         if(link>=links){
1031           return null;
1032         }
1033         else{
1034           return vi[link];
1035         }
1036       }
1037     }
1038     else{
1039       if(decode_ready){
1040         return vi[0];
1041       }
1042       else{
1043         return null;
1044       }
1045     }
1046   }
1047
1048   public Comment comment(int link){
1049     if(seekable){
1050       if(link<0){
1051         if(decode_ready){ return vc[current_link]; }
1052         else{ return null; }
1053       }
1054       else{
1055         if(link>=links){ return null;}
1056         else{ return vc[link]; }
1057       }
1058     }
1059     else{
1060       if(decode_ready){ return vc[0]; }
1061       else{ return null; }
1062     }
1063   }
1064
1065   int host_is_big_endian() {
1066     return 1;
1067 //    short pattern = 0xbabe;
1068 //    unsigned char *bytewise = (unsigned char *)&pattern;
1069 //    if (bytewise[0] == 0xba) return 1;
1070 //    assert(bytewise[0] == 0xbe);
1071 //    return 0;
1072   }
1073
1074   // up to this point, everything could more or less hide the multiple
1075   // logical bitstream nature of chaining from the toplevel application
1076   // if the toplevel application didn't particularly care.  However, at
1077   // the point that we actually read audio back, the multiple-section
1078   // nature must surface: Multiple bitstream sections do not necessarily
1079   // have to have the same number of channels or sampling rate.
1080   // 
1081   // read returns the sequential logical bitstream number currently
1082   // being decoded along with the PCM data in order that the toplevel
1083   // application can take action on channel/sample rate changes.  This
1084   // number will be incremented even for streamed (non-seekable) streams
1085   // (for seekable streams, it represents the actual logical bitstream
1086   // index within the physical bitstream.  Note that the accessor
1087   // functions above are aware of this dichotomy).
1088   //
1089   // input values: buffer) a buffer to hold packed PCM data for return
1090   //               length) the byte length requested to be placed into buffer
1091   //               bigendianp) should the data be packed LSB first (0) or
1092   //                           MSB first (1)
1093   //               word) word size for output.  currently 1 (byte) or 
1094   //                     2 (16 bit short)
1095   // 
1096   // return values: -1) error/hole in data
1097   //                 0) EOF
1098   //                 n) number of bytes of PCM actually returned.  The
1099   //                    below works on a packet-by-packet basis, so the
1100   //                    return length is not related to the 'length' passed
1101   //                    in, just guaranteed to fit.
1102   // 
1103   // *section) set to the logical bitstream number
1104
1105   int read(byte[] buffer,int length,
1106            int bigendianp, int word, int sgned, int[] bitstream){
1107     int host_endian = host_is_big_endian();
1108     int index=0;
1109
1110     while(true){
1111       if(decode_ready){
1112         float[][] pcm;
1113         float[][][] _pcm=new float[1][][];
1114         int[] _index=new int[info(-1).channels];
1115         int samples=vd.synthesis_pcmout(_pcm, _index);
1116         pcm=_pcm[0];
1117         if(samples!=0){
1118           // yay! proceed to pack data into the byte buffer
1119           int channels=info(-1).channels;
1120           int bytespersample=word * channels;
1121           if(samples>length/bytespersample)samples=length/bytespersample;
1122         
1123           // a tight loop to pack each size
1124           {
1125             int val;
1126             if(word==1){
1127               int off=(sgned!=0?0:128);
1128               for(int j=0;j<samples;j++){
1129                 for(int i=0;i<channels;i++){
1130                   val=(int)(pcm[i][_index[i]+j]*128. + 0.5);
1131                   if(val>127)val=127;
1132                   else if(val<-128)val=-128;
1133                   buffer[index++]=(byte)(val+off);
1134                 }
1135               }
1136             }
1137             else{
1138               int off=(sgned!=0?0:32768);
1139
1140               if(host_endian==bigendianp){
1141                 if(sgned!=0){
1142                   for(int i=0;i<channels;i++) { // It's faster in this order
1143                     int src=_index[i];
1144                     int dest=i;
1145                     for(int j=0;j<samples;j++) {
1146                       val=(int)(pcm[i][src+j]*32768. + 0.5);
1147                       if(val>32767)val=32767;
1148                       else if(val<-32768)val=-32768;
1149                       buffer[dest]=(byte)(val>>>8);
1150                       buffer[dest+1]=(byte)(val);
1151                       dest+=channels*2;
1152                     }
1153                   }
1154                 }
1155                 else{
1156                   for(int i=0;i<channels;i++) {
1157                     float[] src=pcm[i];
1158                     int dest=i;
1159                     for(int j=0;j<samples;j++) {
1160                       val=(int)(src[j]*32768. + 0.5);
1161                       if(val>32767)val=32767;
1162                       else if(val<-32768)val=-32768;
1163                       buffer[dest]=(byte)((val+off)>>>8);
1164                       buffer[dest+1]=(byte)(val+off);
1165                       dest+=channels*2;
1166                     }
1167                   }
1168                 }
1169               }
1170               else if(bigendianp!=0){
1171                 for(int j=0;j<samples;j++){
1172                   for(int i=0;i<channels;i++){
1173                     val=(int)(pcm[i][j]*32768. + 0.5);
1174                     if(val>32767)val=32767;
1175                     else if(val<-32768)val=-32768;
1176                     val+=off;
1177                     buffer[index++]=(byte)(val>>>8);
1178                     buffer[index++]=(byte)val;
1179                   }
1180                 }
1181               }
1182               else{
1183                 //int val;
1184                 for(int j=0;j<samples;j++){
1185                   for(int i=0;i<channels;i++){
1186                     val=(int)(pcm[i][j]*32768. + 0.5);
1187                     if(val>32767)val=32767;
1188                     else if(val<-32768)val=-32768;
1189                     val+=off;
1190                     buffer[index++]=(byte)val;
1191                     buffer[index++]=(byte)(val>>>8);
1192                   }
1193                 }
1194               }
1195             }
1196           }
1197         
1198           vd.synthesis_read(samples);
1199           pcm_offset+=samples;
1200           if(bitstream!=null)bitstream[0]=current_link;
1201           return(samples*bytespersample);
1202         }
1203       }
1204
1205       // suck in another packet
1206       switch(process_packet(1)){
1207       case 0:
1208         return(0);
1209       case -1:
1210         return -1;
1211       default:
1212         break;
1213       }
1214     }
1215   }
1216
1217   public int getLinks(){return links;}
1218   public Info[] getInfo(){return vi;}
1219   public Comment[] getComment(){return vc;}
1220
1221   public static void main(String[] arg){
1222     try{
1223       VorbisFile foo=new VorbisFile(arg[0]);
1224       int links=foo.getLinks();
1225       System.out.println("links="+links);
1226       Comment[] comment=foo.getComment();
1227       Info[] info=foo.getInfo();
1228       for(int i=0; i<links; i++){
1229         System.out.println(info[i]);
1230         System.out.println(comment[i]);
1231       }
1232       System.out.println("raw_total: "+foo.raw_total(-1));
1233       System.out.println("pcm_total: "+foo.pcm_total(-1));
1234       System.out.println("time_total: "+foo.time_total(-1));
1235     }
1236     catch(Exception e){
1237       System.err.println(e);
1238     }
1239   }
1240 }
This page took 0.188156 seconds and 4 git commands to generate.