]> Joshua Wise's Git repositories - patchfork.git/blob - jorbis/src/com/jcraft/jogg/StreamState.java
initial import from pitchfork-0.5.5
[patchfork.git] / jorbis / src / com / jcraft / jogg / StreamState.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.jogg;
27
28 public class StreamState{
29   byte[] body_data;    /* bytes from packet bodies */
30   int body_storage;    /* storage elements allocated */
31   int body_fill;       /* elements stored; fill mark */
32 private  int body_returned;   /* elements of fill returned */
33
34
35   int[] lacing_vals;    /* The values that will go to the segment table */
36   long[] granule_vals;  /* pcm_pos values for headers. Not compact
37                            this way, but it is simple coupled to the
38                            lacing fifo */
39   int lacing_storage;
40   int lacing_fill;
41   int lacing_packet;
42   int lacing_returned;
43
44   byte[] header=new byte[282];      /* working space for header encode */
45   int header_fill;
46
47   public int e_o_s;   /* set when we have buffered the last packet in the
48                          logical bitstream */
49   int b_o_s;          /* set after we've written the initial page
50                          of a logical bitstream */
51   int serialno;
52   int pageno;
53   long packetno;      /* sequence number for decode; the framing
54                          knows where there's a hole in the data,
55                          but we need coupling so that the codec
56                          (which is in a seperate abstraction
57                          layer) also knows about the gap */
58   long granulepos;
59
60   public StreamState(){
61     init();
62   }
63
64   StreamState(int serialno){
65     this();
66     init(serialno);
67   }
68   void init(){
69     body_storage=16*1024;
70     body_data=new byte[body_storage];
71     lacing_storage=1024;
72     lacing_vals=new int[lacing_storage];
73     granule_vals=new long[lacing_storage];
74   }
75   public void init(int serialno){
76     if(body_data==null){ init(); }
77     else{
78       for(int i=0; i<body_data.length; i++) body_data[i]=0;
79       for(int i=0; i<lacing_vals.length; i++) lacing_vals[i]=0;
80       for(int i=0; i<granule_vals.length; i++) granule_vals[i]=0;
81     }
82     this.serialno=serialno;
83   }
84   public void clear(){
85     body_data=null;
86     lacing_vals=null;
87     granule_vals=null;
88     //memset(os,0,sizeof(ogg_stream_state));    
89   }
90   void destroy(){
91     clear();
92   }
93   void body_expand(int needed){
94     if(body_storage<=body_fill+needed){
95       body_storage+=(needed+1024);
96       byte[] foo=new byte[body_storage];
97       System.arraycopy(body_data, 0, foo, 0, body_data.length);
98       body_data=foo;
99 //System.out.println("expand: body_fill="+body_fill+", body_storage="+body_data.length);
100     }
101   }
102   void lacing_expand(int needed){
103     if(lacing_storage<=lacing_fill+needed){
104       lacing_storage+=(needed+32);
105       int[] foo=new int[lacing_storage];
106       System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
107       lacing_vals=foo;
108
109       long[] bar=new long[lacing_storage];
110       System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
111       granule_vals=bar;
112     }
113   }
114
115   /* submit data to the internal buffer of the framing engine */
116   public int packetin(Packet op){
117     int lacing_val=op.bytes/255+1;
118
119     if(body_returned!=0){
120       /* advance packet data according to the body_returned pointer. We
121          had to keep it around to return a pointer into the buffer last
122          call */
123     
124       body_fill-=body_returned;
125       if(body_fill!=0){
126 //        memmove(os->body_data,os->body_data+os->body_returned,
127 //              os->body_fill*sizeof(char));
128         System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
129       }
130       body_returned=0;
131     }
132
133     /* make sure we have the buffer storage */
134     body_expand(op.bytes);
135     lacing_expand(lacing_val);
136
137   /* Copy in the submitted packet.  Yes, the copy is a waste; this is
138      the liability of overly clean abstraction for the time being.  It
139      will actually be fairly easy to eliminate the extra copy in the
140      future */
141
142     System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes);
143     body_fill+=op.bytes;
144 //System.out.println("add: "+body_fill);
145
146   /* Store lacing vals for this packet */
147     int j;
148     for(j=0;j<lacing_val-1;j++){
149       lacing_vals[lacing_fill+j]=255;
150       granule_vals[lacing_fill+j]=granulepos;
151     }
152     lacing_vals[lacing_fill+j]=(op.bytes)%255;
153     granulepos=granule_vals[lacing_fill+j]=op.granulepos;
154
155   /* flag the first segment as the beginning of the packet */
156     lacing_vals[lacing_fill]|= 0x100;
157
158     lacing_fill+=lacing_val;
159
160   /* for the sake of completeness */
161     packetno++;
162
163     if(op.e_o_s!=0)e_o_s=1;
164     return(0);
165   }
166
167   public int packetout(Packet op){
168
169   /* The last part of decode. We have the stream broken into packet
170      segments.  Now we need to group them into packets (or return the
171      out of sync markers) */
172
173     int ptr=lacing_returned;
174
175     if(lacing_packet<=ptr){
176       return(0);
177     }
178
179     if((lacing_vals[ptr]&0x400)!=0){
180     /* We lost sync here; let the app know */
181       lacing_returned++;
182
183     /* we need to tell the codec there's a gap; it might need to
184        handle previous packet dependencies. */
185       packetno++;
186       return(-1);
187     }
188
189   /* Gather the whole packet. We'll have no holes or a partial packet */
190     {
191       int size=lacing_vals[ptr]&0xff;
192       int bytes=0;
193
194       op.packet_base=body_data;
195       op.packet=body_returned;
196       op.e_o_s=lacing_vals[ptr]&0x200; /* last packet of the stream? */
197       op.b_o_s=lacing_vals[ptr]&0x100; /* first packet of the stream? */
198       bytes+=size;
199
200       while(size==255){
201         int val=lacing_vals[++ptr];
202         size=val&0xff;
203         if((val&0x200)!=0)op.e_o_s=0x200;
204         bytes+=size;
205       }
206
207       op.packetno=packetno;
208       op.granulepos=granule_vals[ptr];
209       op.bytes=bytes;
210
211 //System.out.println(this+" # body_returned="+body_returned);
212       body_returned+=bytes;
213 //System.out.println(this+"## body_returned="+body_returned);
214
215       lacing_returned=ptr+1;
216     }
217     packetno++;
218     return(1);
219   }
220
221
222   // add the incoming page to the stream state; we decompose the page
223   // into packet segments here as well.
224
225   public int pagein(Page og){
226     byte[] header_base=og.header_base;
227     int header=og.header;
228     byte[] body_base=og.body_base;
229     int body=og.body;
230     int bodysize=og.body_len;
231     int segptr=0;
232
233     int version=og.version();
234     int continued=og.continued();
235     int bos=og.bos();
236     int eos=og.eos();
237     long granulepos=og.granulepos();
238     int _serialno=og.serialno();
239     int _pageno=og.pageno();
240     int segments=header_base[header+26]&0xff;
241
242     // clean up 'returned data'
243     {
244       int lr=lacing_returned;
245       int br=body_returned;
246
247       // body data
248
249 //System.out.println("br="+br+", body_fill="+body_fill);
250
251       if(br!=0){
252         body_fill-=br;
253         if(body_fill!=0){
254           System.arraycopy(body_data, br, body_data, 0, body_fill);
255         }
256         body_returned=0;
257       }
258
259 //System.out.println("?? br="+br+", body_fill="+body_fill+" body_returned="+body_returned);
260
261       if(lr!=0){
262         // segment table
263         if((lacing_fill-lr)!=0){
264           System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill-lr);
265           System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill-lr);
266         }
267         lacing_fill-=lr;
268         lacing_packet-=lr;
269         lacing_returned=0;
270       }
271     }
272
273     // check the serial number
274     if(_serialno!=serialno)return(-1);
275     if(version>0)return(-1);
276
277     lacing_expand(segments+1);
278
279     // are we in sequence?
280     if(_pageno!=pageno){
281       int i;
282
283       // unroll previous partial packet (if any)
284       for(i=lacing_packet;i<lacing_fill;i++){
285         body_fill-=lacing_vals[i]&0xff;
286 //System.out.println("??");
287       }
288       lacing_fill=lacing_packet;
289
290       // make a note of dropped data in segment table
291       if(pageno!=-1){
292         lacing_vals[lacing_fill++]=0x400;
293         lacing_packet++;
294       }
295
296       // are we a 'continued packet' page?  If so, we'll need to skip
297       // some segments
298       if(continued!=0){
299         bos=0;
300         for(;segptr<segments;segptr++){
301           int val=(header_base[header+27+segptr]&0xff);
302           body+=val;
303           bodysize-=val;
304           if(val<255){
305             segptr++;
306             break;
307           }
308         }
309       }
310     }
311
312 //System.out.println("bodysize="+bodysize);
313
314     if(bodysize!=0){
315       body_expand(bodysize);
316       System.arraycopy(body_base, body, body_data, body_fill, bodysize);
317       body_fill+=bodysize;
318     }
319
320 //System.out.println("bodyfill="+body_fill);
321
322     {
323       int saved=-1;
324       while(segptr<segments){
325         int val=(header_base[header+27+segptr]&0xff);
326         lacing_vals[lacing_fill]=val;
327         granule_vals[lacing_fill]=-1;
328       
329         if(bos!=0){
330           lacing_vals[lacing_fill]|=0x100;
331           bos=0;
332         }
333       
334         if(val<255)saved=lacing_fill;
335       
336         lacing_fill++;
337         segptr++;
338       
339         if(val<255)lacing_packet=lacing_fill;
340       }
341   
342     /* set the granulepos on the last pcmval of the last full packet */
343       if(saved!=-1){
344         granule_vals[saved]=granulepos;
345       }
346     }
347
348     if(eos!=0){
349       e_o_s=1;
350       if(lacing_fill>0)
351         lacing_vals[lacing_fill-1]|=0x200;
352     }
353
354     pageno=_pageno+1;
355     return(0);
356   }
357
358
359 /* This will flush remaining packets into a page (returning nonzero),
360    even if there is not enough data to trigger a flush normally
361    (undersized page). If there are no packets or partial packets to
362    flush, ogg_stream_flush returns 0.  Note that ogg_stream_flush will
363    try to flush a normal sized page like ogg_stream_pageout; a call to
364    ogg_stream_flush does not gurantee that all packets have flushed.
365    Only a return value of 0 from ogg_stream_flush indicates all packet
366    data is flushed into pages.
367
368    ogg_stream_page will flush the last page in a stream even if it's
369    undersized; you almost certainly want to use ogg_stream_pageout
370    (and *not* ogg_stream_flush) unless you need to flush an undersized
371    page in the middle of a stream for some reason. */
372
373   public int flush(Page og){
374
375 //System.out.println(this+" ---body_returned: "+body_returned);
376
377     int i;
378     int vals=0;
379     int maxvals=(lacing_fill>255?255:lacing_fill);
380     int bytes=0;
381     int acc=0;
382     long granule_pos=granule_vals[0];
383
384     if(maxvals==0)return(0);
385   
386     /* construct a page */
387     /* decide how many segments to include */
388   
389     /* If this is the initial header case, the first page must only include
390        the initial header packet */
391     if(b_o_s==0){  /* 'initial header page' case */
392       granule_pos=0;
393       for(vals=0;vals<maxvals;vals++){
394         if((lacing_vals[vals]&0x0ff)<255){
395           vals++;
396           break;
397         }
398       }
399     }
400     else{
401       for(vals=0;vals<maxvals;vals++){
402         if(acc>4096)break;
403         acc+=(lacing_vals[vals]&0x0ff);
404         granule_pos=granule_vals[vals];
405       }
406     }
407
408     /* construct the header in temp storage */
409     System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
410   
411     /* stream structure version */
412     header[4]=0x00;
413
414     /* continued packet flag? */
415     header[5]=0x00;
416     if((lacing_vals[0]&0x100)==0)header[5]|=0x01;
417     /* first page flag? */
418     if(b_o_s==0) header[5]|=0x02;
419     /* last page flag? */
420     if(e_o_s!=0 && lacing_fill==vals) header[5]|=0x04;
421     b_o_s=1;
422
423     /* 64 bits of PCM position */
424     for(i=6;i<14;i++){
425       header[i]=(byte)granule_pos;
426       granule_pos>>>=8;
427     }
428
429     /* 32 bits of stream serial number */
430     {
431       int _serialno=serialno;
432       for(i=14;i<18;i++){
433         header[i]=(byte)_serialno;
434         _serialno>>>=8;
435       }
436     }
437
438     /* 32 bits of page counter (we have both counter and page header
439        because this val can roll over) */
440     if(pageno==-1)pageno=0;       /* because someone called
441                                      stream_reset; this would be a
442                                      strange thing to do in an
443                                      encode stream, but it has
444                                      plausible uses */
445     {
446       int _pageno=pageno++;
447       for(i=18;i<22;i++){
448         header[i]=(byte)_pageno;
449         _pageno>>>=8;
450       }
451     }
452   
453     /* zero for computation; filled in later */
454     header[22]=0;
455     header[23]=0;
456     header[24]=0;
457     header[25]=0;
458   
459     /* segment table */
460     header[26]=(byte)vals;
461     for(i=0;i<vals;i++){
462       header[i+27]=(byte)lacing_vals[i];
463       bytes+=(header[i+27]&0xff);
464     }
465   
466     /* set pointers in the ogg_page struct */
467     og.header_base=header;
468     og.header=0;
469     og.header_len=header_fill=vals+27;
470     og.body_base=body_data;
471     og.body=body_returned;
472     og.body_len=bytes;
473
474     /* advance the lacing data and set the body_returned pointer */
475   
476 //System.out.println("###body_returned: "+body_returned);
477
478     lacing_fill-=vals;
479     System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill*4);
480     System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill*8);
481     body_returned+=bytes;
482
483 //System.out.println("####body_returned: "+body_returned);
484   
485     /* calculate the checksum */
486   
487     og.checksum();
488
489     /* done */
490     return(1);
491   }
492
493
494 /* This constructs pages from buffered packet segments.  The pointers
495 returned are to static buffers; do not free. The returned buffers are
496 good only until the next call (using the same ogg_stream_state) */
497   public int pageout(Page og){
498 //    if(body_returned!=0){
499 //    /* advance packet data according to the body_returned pointer. We
500 //       had to keep it around to return a pointer into the buffer last
501 //       call */
502 //
503 //      body_fill-=body_returned;
504 //      if(body_fill!=0){ // overlap?
505 //      System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
506 //      }
507 //      body_returned=0;
508 //    }
509 //
510 //System.out.println("pageout: e_o_s="+e_o_s+" lacing_fill="+lacing_fill+" body_fill="+body_fill+", lacing_fill="+lacing_fill+" b_o_s="+b_o_s);
511 //
512 //    if((e_o_s!=0&&lacing_fill!=0) ||  /* 'were done, now flush' case */
513 //       body_fill > 4096 ||          /* 'page nominal size' case */
514 //       lacing_fill>=255 ||          /* 'segment table full' case */
515 //       (lacing_fill!=0&&b_o_s==0)){  /* 'initial header page' case */
516 //      int vals=0,bytes=0;
517 //      int maxvals=(lacing_fill>255?255:lacing_fill);
518 //      long acc=0;
519 //      long pcm_pos=granule_vals[0];
520 //
521 //    /* construct a page */
522 //    /* decide how many segments to include */
523 //
524 //    /* If this is the initial header case, the first page must only include
525 //       the initial header packet */
526 //      if(b_o_s==0){  /* 'initial header page' case */
527 //        pcm_pos=0;
528 //        for(vals=0;vals<maxvals;vals++){
529 //        if((lacing_vals[vals]&0x0ff)<255){
530 //          vals++;
531 //          break;
532 //        }
533 //        }
534 //      }
535 //      else{
536 //        for(vals=0;vals<maxvals;vals++){
537 //        if(acc>4096)break;
538 //        acc+=lacing_vals[vals]&0x0ff;
539 //        pcm_pos=granule_vals[vals];
540 //        }
541 //      }
542 //
543 //    /* construct the header in temp storage */
544 //      System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
545 //
546 //    /* stream structure version */
547 //      header[4]=0x00;
548 //    
549 //    /* continued packet flag? */
550 //      header[5]=0x00;
551 //      if((lacing_vals[0]&0x100)==0)header[5]|=0x01;
552 //    /* first page flag? */
553 //      if(b_o_s==0)header[5]|=0x02;
554 //    /* last page flag? */
555 //      if(e_o_s!=0 && lacing_fill==vals)header[5]|=0x04;
556 //      b_o_s=1;
557 //
558 //    /* 64 bits of PCM position */
559 //      for(int i=6;i<14;i++){
560 //        header[i]=(byte)pcm_pos;
561 //        pcm_pos>>>=8;
562 //      }
563 //
564 //    /* 32 bits of stream serial number */
565 //      {
566 //        int serialn=serialno;
567 //        for(int i=14;i<18;i++){
568 //        header[i]=(byte)serialn;
569 //        serialn>>>=8;
570 //        }
571 //      }
572 //
573 //
574 ///* 32 bits of page counter (we have both counter and page header
575 //       because this val can roll over) */
576 //      if(pageno==-1)pageno=0; /* because someone called
577 //                                       stream_reset; this would be a
578 //                                       strange thing to do in an
579 //                                       encode stream, but it has
580 //                                       plausible uses */
581 //      {
582 //        int pagen=pageno++;
583 //        for(int i=18;i<22;i++){
584 //        header[i]=(byte)pagen;
585 //        pagen>>>=8;
586 //        }
587 //      }
588 //
589 //    /* zero for computation; filled in later */
590 //      header[22]=0;
591 //      header[23]=0;
592 //      header[24]=0;
593 //      header[25]=0;
594 //
595 //    /* segment table */
596 //      header[26]=(byte)vals;
597 //      for(int i=0;i<vals;i++){
598 //        header[i+27]=(byte)lacing_vals[i];
599 //        bytes+=header[i+27]&0xff;
600 ////      bytes+=header[i+27]=(lacing_vals[i]&0xff);
601 //      }
602 //      
603 //    /* advance the lacing data and set the body_returned pointer */
604 //
605 //      lacing_fill-=vals;
606 //      System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill);
607 //      System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill);
608 //      body_returned=bytes;
609 //
610 //    /* set pointers in the ogg_page struct */
611 //      og.header_base=header;
612 //      og.header=0;
613 //      og.header_len=header_fill=vals+27;
614 //
615 //      og.body_base=body_data;
616 //      og.body=0;
617 //      og.body_len=bytes;
618 //
619 //    /* calculate the checksum */
620 //
621 //      og.checksum();
622 //      return(1);
623 //    }
624 //    /* not enough data to construct a page and not end of stream */
625 //    return(0);
626 //System.out.println("pageout: "+body_returned);
627     if((e_o_s!=0&&lacing_fill!=0) ||  /* 'were done, now flush' case */
628         body_fill-body_returned> 4096 ||     /* 'page nominal size' case */
629         lacing_fill>=255 ||          /* 'segment table full' case */
630         (lacing_fill!=0&&b_o_s==0)){  /* 'initial header page' case */
631       return flush(og);
632     }
633     return 0;
634   }
635
636   public int eof(){
637     return e_o_s;
638   }
639
640   public int reset(){
641     body_fill=0;
642     body_returned=0;
643
644     lacing_fill=0;
645     lacing_packet=0;
646     lacing_returned=0;
647
648     header_fill=0;
649
650     e_o_s=0;
651     b_o_s=0;
652     pageno=-1;
653     packetno=0;
654     granulepos=0;
655     return(0);
656   }
657 }
This page took 0.057095 seconds and 4 git commands to generate.