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}