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