2 * Copyright (C) 2000 ymnk, JCraft,Inc.
4 * Written by: 2000 ymnk<ymnk@jcraft.com>
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.
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.
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.
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.
26 package com.jcraft.jogg;
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 */
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
44 byte[] header=new byte[282]; /* working space for header encode */
47 public int e_o_s; /* set when we have buffered the last packet in the
49 int b_o_s; /* set after we've written the initial page
50 of a logical bitstream */
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 */
64 StreamState(int serialno){
70 body_data=new byte[body_storage];
72 lacing_vals=new int[lacing_storage];
73 granule_vals=new long[lacing_storage];
75 public void init(int serialno){
76 if(body_data==null){ init(); }
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;
82 this.serialno=serialno;
88 //memset(os,0,sizeof(ogg_stream_state));
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);
99 //System.out.println("expand: body_fill="+body_fill+", body_storage="+body_data.length);
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);
109 long[] bar=new long[lacing_storage];
110 System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
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;
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
124 body_fill-=body_returned;
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);
133 /* make sure we have the buffer storage */
134 body_expand(op.bytes);
135 lacing_expand(lacing_val);
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
142 System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes);
144 //System.out.println("add: "+body_fill);
146 /* Store lacing vals for this packet */
148 for(j=0;j<lacing_val-1;j++){
149 lacing_vals[lacing_fill+j]=255;
150 granule_vals[lacing_fill+j]=granulepos;
152 lacing_vals[lacing_fill+j]=(op.bytes)%255;
153 granulepos=granule_vals[lacing_fill+j]=op.granulepos;
155 /* flag the first segment as the beginning of the packet */
156 lacing_vals[lacing_fill]|= 0x100;
158 lacing_fill+=lacing_val;
160 /* for the sake of completeness */
163 if(op.e_o_s!=0)e_o_s=1;
167 public int packetout(Packet op){
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) */
173 int ptr=lacing_returned;
175 if(lacing_packet<=ptr){
179 if((lacing_vals[ptr]&0x400)!=0){
180 /* We lost sync here; let the app know */
183 /* we need to tell the codec there's a gap; it might need to
184 handle previous packet dependencies. */
189 /* Gather the whole packet. We'll have no holes or a partial packet */
191 int size=lacing_vals[ptr]&0xff;
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? */
201 int val=lacing_vals[++ptr];
203 if((val&0x200)!=0)op.e_o_s=0x200;
207 op.packetno=packetno;
208 op.granulepos=granule_vals[ptr];
211 //System.out.println(this+" # body_returned="+body_returned);
212 body_returned+=bytes;
213 //System.out.println(this+"## body_returned="+body_returned);
215 lacing_returned=ptr+1;
222 // add the incoming page to the stream state; we decompose the page
223 // into packet segments here as well.
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;
230 int bodysize=og.body_len;
233 int version=og.version();
234 int continued=og.continued();
237 long granulepos=og.granulepos();
238 int _serialno=og.serialno();
239 int _pageno=og.pageno();
240 int segments=header_base[header+26]&0xff;
242 // clean up 'returned data'
244 int lr=lacing_returned;
245 int br=body_returned;
249 //System.out.println("br="+br+", body_fill="+body_fill);
254 System.arraycopy(body_data, br, body_data, 0, body_fill);
259 //System.out.println("?? br="+br+", body_fill="+body_fill+" body_returned="+body_returned);
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);
273 // check the serial number
274 if(_serialno!=serialno)return(-1);
275 if(version>0)return(-1);
277 lacing_expand(segments+1);
279 // are we in sequence?
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("??");
288 lacing_fill=lacing_packet;
290 // make a note of dropped data in segment table
292 lacing_vals[lacing_fill++]=0x400;
296 // are we a 'continued packet' page? If so, we'll need to skip
300 for(;segptr<segments;segptr++){
301 int val=(header_base[header+27+segptr]&0xff);
312 //System.out.println("bodysize="+bodysize);
315 body_expand(bodysize);
316 System.arraycopy(body_base, body, body_data, body_fill, bodysize);
320 //System.out.println("bodyfill="+body_fill);
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;
330 lacing_vals[lacing_fill]|=0x100;
334 if(val<255)saved=lacing_fill;
339 if(val<255)lacing_packet=lacing_fill;
342 /* set the granulepos on the last pcmval of the last full packet */
344 granule_vals[saved]=granulepos;
351 lacing_vals[lacing_fill-1]|=0x200;
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.
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. */
373 public int flush(Page og){
375 //System.out.println(this+" ---body_returned: "+body_returned);
379 int maxvals=(lacing_fill>255?255:lacing_fill);
382 long granule_pos=granule_vals[0];
384 if(maxvals==0)return(0);
386 /* construct a page */
387 /* decide how many segments to include */
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 */
393 for(vals=0;vals<maxvals;vals++){
394 if((lacing_vals[vals]&0x0ff)<255){
401 for(vals=0;vals<maxvals;vals++){
403 acc+=(lacing_vals[vals]&0x0ff);
404 granule_pos=granule_vals[vals];
408 /* construct the header in temp storage */
409 System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
411 /* stream structure version */
414 /* continued packet flag? */
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;
423 /* 64 bits of PCM position */
425 header[i]=(byte)granule_pos;
429 /* 32 bits of stream serial number */
431 int _serialno=serialno;
433 header[i]=(byte)_serialno;
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
446 int _pageno=pageno++;
448 header[i]=(byte)_pageno;
453 /* zero for computation; filled in later */
460 header[26]=(byte)vals;
462 header[i+27]=(byte)lacing_vals[i];
463 bytes+=(header[i+27]&0xff);
466 /* set pointers in the ogg_page struct */
467 og.header_base=header;
469 og.header_len=header_fill=vals+27;
470 og.body_base=body_data;
471 og.body=body_returned;
474 /* advance the lacing data and set the body_returned pointer */
476 //System.out.println("###body_returned: "+body_returned);
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;
483 //System.out.println("####body_returned: "+body_returned);
485 /* calculate the checksum */
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
503 // body_fill-=body_returned;
504 // if(body_fill!=0){ // overlap?
505 // System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
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);
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);
519 // long pcm_pos=granule_vals[0];
521 // /* construct a page */
522 // /* decide how many segments to include */
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 */
528 // for(vals=0;vals<maxvals;vals++){
529 // if((lacing_vals[vals]&0x0ff)<255){
536 // for(vals=0;vals<maxvals;vals++){
537 // if(acc>4096)break;
538 // acc+=lacing_vals[vals]&0x0ff;
539 // pcm_pos=granule_vals[vals];
543 // /* construct the header in temp storage */
544 // System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
546 // /* stream structure version */
549 // /* continued packet flag? */
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;
558 // /* 64 bits of PCM position */
559 // for(int i=6;i<14;i++){
560 // header[i]=(byte)pcm_pos;
564 // /* 32 bits of stream serial number */
566 // int serialn=serialno;
567 // for(int i=14;i<18;i++){
568 // header[i]=(byte)serialn;
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
582 // int pagen=pageno++;
583 // for(int i=18;i<22;i++){
584 // header[i]=(byte)pagen;
589 // /* zero for computation; filled in later */
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);
603 // /* advance the lacing data and set the body_returned pointer */
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;
610 // /* set pointers in the ogg_page struct */
611 // og.header_base=header;
613 // og.header_len=header_fill=vals+27;
615 // og.body_base=body_data;
617 // og.body_len=bytes;
619 // /* calculate the checksum */
624 // /* not enough data to construct a page and not end of stream */
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 */