]> Joshua Wise's Git repositories - patchfork.git/blame - jorbis/src/com/jcraft/jorbis/VorbisFile.java.new
Add support for view-only mode.
[patchfork.git] / jorbis / src / com / jcraft / jorbis / VorbisFile.java.new
CommitLineData
964dd0bc
JW
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
26package com.jcraft.jorbis;
27
28import com.jcraft.jogg.*;
29import java.io.InputStream;
30
31public 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();
338System.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
370System.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){
410System.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
607System.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
612System.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){
702System.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){
759System.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 }
767System.out.println("#1");
768 // clear out decoding machine state
769 pcm_offset=-1;
770System.out.println("#2");
771 decode_clear();
772System.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
781System.out.println("#4");
782 switch(process_packet(1)){
783 case 0:
784System.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:
790System.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:
797System.out.println("?break");
798 // all OK
799 break;
800 }
801System.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.20859 seconds and 5 git commands to generate.