001/* JOrbis
002 * Copyright (C) 2000 ymnk, JCraft,Inc.
003 *  
004 * Written by: 2000 ymnk<ymnk@jcaft.com>
005 *   
006 * Many thanks to 
007 *   Monty <monty@xiph.org> and 
008 *   The XIPHOPHORUS Company http://www.xiph.org/ .
009 * JOrbis has been based on their awesome works, Vorbis codec.
010 *   
011 * This program is free software; you can redistribute it and/or
012 * modify it under the terms of the GNU Library General Public License
013 * as published by the Free Software Foundation; either version 2 of
014 * the License, or (at your option) any later version.
015   
016 * This program is distributed in the hope that it will be useful,
017 * but WITHOUT ANY WARRANTY; without even the implied warranty of
018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
019 * GNU Library General Public License for more details.
020 * 
021 * You should have received a copy of the GNU Library General Public
022 * License along with this program; if not, write to the Free Software
023 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
024 */
025
026package com.jcraft.jogg;
027
028public class StreamState{
029  byte[] body_data;    /* bytes from packet bodies */
030  int body_storage;    /* storage elements allocated */
031  int body_fill;       /* elements stored; fill mark */
032private  int body_returned;   /* elements of fill returned */
033
034
035  int[] lacing_vals;    /* The values that will go to the segment table */
036  long[] granule_vals;  /* pcm_pos values for headers. Not compact
037                           this way, but it is simple coupled to the
038                           lacing fifo */
039  int lacing_storage;
040  int lacing_fill;
041  int lacing_packet;
042  int lacing_returned;
043
044  byte[] header=new byte[282];      /* working space for header encode */
045  int header_fill;
046
047  public int e_o_s;   /* set when we have buffered the last packet in the
048                         logical bitstream */
049  int b_o_s;          /* set after we've written the initial page
050                         of a logical bitstream */
051  int serialno;
052  int pageno;
053  long packetno;      /* sequence number for decode; the framing
054                         knows where there's a hole in the data,
055                         but we need coupling so that the codec
056                         (which is in a seperate abstraction
057                         layer) also knows about the gap */
058  long granulepos;
059
060  public StreamState(){
061    init();
062  }
063
064  StreamState(int serialno){
065    this();
066    init(serialno);
067  }
068  void init(){
069    body_storage=16*1024;
070    body_data=new byte[body_storage];
071    lacing_storage=1024;
072    lacing_vals=new int[lacing_storage];
073    granule_vals=new long[lacing_storage];
074  }
075  public void init(int serialno){
076    if(body_data==null){ init(); }
077    else{
078      for(int i=0; i<body_data.length; i++) body_data[i]=0;
079      for(int i=0; i<lacing_vals.length; i++) lacing_vals[i]=0;
080      for(int i=0; i<granule_vals.length; i++) granule_vals[i]=0;
081    }
082    this.serialno=serialno;
083  }
084  public void clear(){
085    body_data=null;
086    lacing_vals=null;
087    granule_vals=null;
088    //memset(os,0,sizeof(ogg_stream_state));    
089  }
090  void destroy(){
091    clear();
092  }
093  void body_expand(int needed){
094    if(body_storage<=body_fill+needed){
095      body_storage+=(needed+1024);
096      byte[] foo=new byte[body_storage];
097      System.arraycopy(body_data, 0, foo, 0, body_data.length);
098      body_data=foo;
099//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
495returned are to static buffers; do not free. The returned buffers are
496good 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}