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 // DECODING PRIMITIVES: packet streaming layer
30 // This has two layers to place more of the multi-serialno and paging
31 // control in the application's hands. First, we expose a data buffer
32 // using ogg_decode_buffer(). The app either copies into the
33 // buffer, or passes it directly to read(), etc. We then call
34 // ogg_decode_wrote() to tell how many bytes we just added.
36 // Pages are returned (pointers into the buffer in ogg_sync_state)
37 // by ogg_decode_stream(). The page is then submitted to
38 // ogg_decode_page() along with the appropriate
39 // ogg_stream_state* (ie, matching serialno). We then get raw
40 // packets out calling ogg_stream_packet() with a
41 // ogg_stream_state. See the 'frame-prog.txt' docs for details and
44 public class SyncState{
61 // byte[] buffer(int size){
62 public int buffer(int size){
63 // first, clear out any space that has been previously returned
67 System.arraycopy(data, returned, data, 0, fill);
72 if(size>storage-fill){
73 // We need to extend the internal buffer
74 int newsize=size+fill+4096; // an extra page to be nice
76 byte[] foo=new byte[newsize];
77 System.arraycopy(data, 0, foo, 0, data.length);
81 data=new byte[newsize];
86 // expose a segment at least as large as requested at the fill mark
87 // return((char *)oy->data+oy->fill);
92 public int wrote(int bytes){
93 if(fill+bytes>storage)return(-1);
98 // sync the stream. This is meant to be useful for finding page
101 // return values for this:
102 // -n) skipped n bytes
103 // 0) page not ready; more data (no bytes skipped)
104 // n) page synced at current location; page length n bytes
105 private Page pageseek=new Page();
106 private byte[] chksum=new byte[4];
107 public int pageseek(Page og){
110 int bytes=fill-returned;
114 if(bytes<27)return(0); // not enough for a header
116 /* verify capture pattern */
118 if(data[page]!='O' ||
125 // search for possible capture
127 for(int ii=0; ii<bytes-1; ii++){
128 if(data[page+1+ii]=='O'){next=page+1+ii; break;}
130 //next=memchr(page+1,'O',bytes-1);
131 if(next==0) next=fill;
134 return(-(next-page));
136 _headerbytes=(data[page+26]&0xff)+27;
137 if(bytes<_headerbytes)return(0); // not enough for header + seg table
139 // count up body length in the segment table
141 for(i=0;i<(data[page+26]&0xff);i++){
142 bodybytes+=(data[page+27+i]&0xff);
144 headerbytes=_headerbytes;
147 if(bodybytes+headerbytes>bytes)return(0);
149 // The whole test page is buffered. Verify the checksum
150 synchronized(chksum){
151 // Grab the checksum bytes, set the header field to zero
153 System.arraycopy(data, page+22, chksum, 0, 4);
159 // set up a temp page struct and recompute the checksum
161 log.header_base=data;
163 log.header_len=headerbytes;
166 log.body=page+headerbytes;
167 log.body_len=bodybytes;
171 if(chksum[0]!=data[page+22] ||
172 chksum[1]!=data[page+23] ||
173 chksum[2]!=data[page+24] ||
174 chksum[3]!=data[page+25]){
175 // D'oh. Mismatch! Corrupt page (or miscapture and not a page at all)
176 // replace the computed checksum with the one actually read in
177 System.arraycopy(chksum, 0, data, page+22, 4);
178 // Bad checksum. Lose sync */
182 // search for possible capture
184 for(int ii=0; ii<bytes-1; ii++){
185 if(data[page+1+ii]=='O'){next=page+1+ii; break;}
187 //next=memchr(page+1,'O',bytes-1);
188 if(next==0) next=fill;
190 return(-(next-page));
194 // yes, have a whole page all ready to go
201 og.header_len=headerbytes;
203 og.body=page+headerbytes;
204 og.body_len=bodybytes;
208 returned+=(bytes=headerbytes+bodybytes);
216 // for(int ii=0; ii<bytes-1; ii++){
217 // if(data[page+1+ii]=='O'){next=page+1+ii;}
219 // //next=memchr(page+1,'O',bytes-1);
220 // if(next==0) next=fill;
222 // return(-(next-page));
226 // sync the stream and get a page. Keep trying until we find a page.
227 // Supress 'sync errors' after reporting the first.
230 // -1) recapture (hole in data)
234 // Returns pointers into buffered data; invalidated by next call to
235 // _stream, _clear, _init, or _buffer
237 public int pageout(Page og){
238 // all we need to do is verify a page at the head of the stream
239 // buffer. If it doesn't verify, we look for the next potential
243 int ret=pageseek(og);
253 // head did not start a synced page... skipped some bytes
258 // loop. keep looking
262 // clear things to an initial state. Good to call, eg, before seeking
273 public int getDataOffset(){ return returned; }
274 public int getBufferOffset(){ return fill; }