]> Joshua Wise's Git repositories - patchfork.git/blame - jorbis/src/com/jcraft/jogg/StreamState.java
initial import from pitchfork-0.5.5
[patchfork.git] / jorbis / src / com / jcraft / jogg / StreamState.java
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.jogg;
27
28public 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 */
32private 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
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}
This page took 0.113884 seconds and 4 git commands to generate.