]>
Commit | Line | Data |
---|---|---|
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 | ||
26 | package com.jcraft.jorbis; | |
27 | ||
28 | import com.jcraft.jogg.*; | |
29 | ||
30 | // Takes a vorbis bitstream from stdin and writes raw stereo PCM to | |
31 | // stdout. Decodes simple and chained OggVorbis files from beginning | |
32 | // to end. Vorbisfile.a is somewhat more complex than the code below. | |
33 | ||
34 | class DecodeExample{ | |
35 | static int convsize=4096*2; | |
36 | static byte[] convbuffer=new byte[convsize]; // take 8k out of the data segment, not the stack | |
37 | ||
38 | public static void main(String[] arg){ | |
39 | java.io.InputStream input=System.in; | |
40 | if(arg.length>0){ | |
41 | try{ | |
42 | input=new java.io.FileInputStream(arg[0]); | |
43 | } | |
44 | catch(Exception e){ | |
45 | System.err.println(e); | |
46 | } | |
47 | } | |
48 | ||
49 | SyncState oy=new SyncState(); // sync and verify incoming physical bitstream | |
50 | StreamState os=new StreamState(); // take physical pages, weld into a logical stream of packets | |
51 | Page og=new Page(); // one Ogg bitstream page. Vorbis packets are inside | |
52 | Packet op=new Packet(); // one raw packet of data for decode | |
53 | ||
54 | Info vi=new Info(); // struct that stores all the static vorbis bitstream settings | |
55 | Comment vc=new Comment(); // struct that stores all the bitstream user comments | |
56 | DspState vd=new DspState(); // central working state for the packet->PCM decoder | |
57 | Block vb=new Block(vd); // local working space for packet->PCM decode | |
58 | ||
59 | byte[] buffer; | |
60 | int bytes=0; | |
61 | ||
62 | // Decode setup | |
63 | ||
64 | oy.init(); // Now we can read pages | |
65 | ||
66 | while(true){ // we repeat if the bitstream is chained | |
67 | int eos=0; | |
68 | ||
69 | // grab some data at the head of the stream. We want the first page | |
70 | // (which is guaranteed to be small and only contain the Vorbis | |
71 | // stream initial header) We need the first page to get the stream | |
72 | // serialno. | |
73 | ||
74 | // submit a 4k block to libvorbis' Ogg layer | |
75 | int index=oy.buffer(4096); | |
76 | buffer=oy.data; | |
77 | try{ | |
78 | bytes=input.read(buffer, index, 4096); | |
79 | } | |
80 | catch(Exception e){ | |
81 | System.err.println(e); | |
82 | System.exit(-1); | |
83 | } | |
84 | oy.wrote(bytes); | |
85 | ||
86 | // Get the first page. | |
87 | if(oy.pageout(og)!=1){ | |
88 | // have we simply run out of data? If so, we're done. | |
89 | if(bytes<4096)break; | |
90 | ||
91 | // error case. Must not be Vorbis data | |
92 | System.err.println("Input does not appear to be an Ogg bitstream."); | |
93 | System.exit(1); | |
94 | } | |
95 | ||
96 | // Get the serial number and set up the rest of decode. | |
97 | // serialno first; use it to set up a logical stream | |
98 | os.init(og.serialno()); | |
99 | ||
100 | // extract the initial header from the first page and verify that the | |
101 | // Ogg bitstream is in fact Vorbis data | |
102 | ||
103 | // I handle the initial header first instead of just having the code | |
104 | // read all three Vorbis headers at once because reading the initial | |
105 | // header is an easy way to identify a Vorbis bitstream and it's | |
106 | // useful to see that functionality seperated out. | |
107 | ||
108 | vi.init(); | |
109 | vc.init(); | |
110 | if(os.pagein(og)<0){ | |
111 | // error; stream version mismatch perhaps | |
112 | System.err.println("Error reading first page of Ogg bitstream data."); | |
113 | System.exit(1); | |
114 | } | |
115 | ||
116 | if(os.packetout(op)!=1){ | |
117 | // no page? must not be vorbis | |
118 | System.err.println("Error reading initial header packet."); | |
119 | System.exit(1); | |
120 | } | |
121 | ||
122 | if(vi.synthesis_headerin(vc,op)<0){ | |
123 | // error case; not a vorbis header | |
124 | System.err.println("This Ogg bitstream does not contain Vorbis audio data."); | |
125 | System.exit(1); | |
126 | } | |
127 | ||
128 | // At this point, we're sure we're Vorbis. We've set up the logical | |
129 | // (Ogg) bitstream decoder. Get the comment and codebook headers and | |
130 | // set up the Vorbis decoder | |
131 | ||
132 | // The next two packets in order are the comment and codebook headers. | |
133 | // They're likely large and may span multiple pages. Thus we reead | |
134 | // and submit data until we get our two pacakets, watching that no | |
135 | // pages are missing. If a page is missing, error out; losing a | |
136 | // header page is the only place where missing data is fatal. */ | |
137 | ||
138 | int i=0; | |
139 | while(i<2){ | |
140 | while(i<2){ | |
141 | ||
142 | int result=oy.pageout(og); | |
143 | if(result==0) break; // Need more data | |
144 | // Don't complain about missing or corrupt data yet. We'll | |
145 | // catch it at the packet output phase | |
146 | ||
147 | if(result==1){ | |
148 | os.pagein(og); // we can ignore any errors here | |
149 | // as they'll also become apparent | |
150 | // at packetout | |
151 | while(i<2){ | |
152 | result=os.packetout(op); | |
153 | if(result==0)break; | |
154 | if(result==-1){ | |
155 | // Uh oh; data at some point was corrupted or missing! | |
156 | // We can't tolerate that in a header. Die. | |
157 | System.err.println("Corrupt secondary header. Exiting."); | |
158 | System.exit(1); | |
159 | } | |
160 | vi.synthesis_headerin(vc,op); | |
161 | i++; | |
162 | } | |
163 | } | |
164 | } | |
165 | // no harm in not checking before adding more | |
166 | index=oy.buffer(4096); | |
167 | buffer=oy.data; | |
168 | try{ | |
169 | bytes=input.read(buffer, index, 4096); | |
170 | } | |
171 | catch(Exception e){ | |
172 | System.err.println(e); | |
173 | System.exit(1); | |
174 | } | |
175 | if(bytes==0 && i<2){ | |
176 | System.err.println("End of file before finding all Vorbis headers!"); | |
177 | System.exit(1); | |
178 | } | |
179 | oy.wrote(bytes); | |
180 | } | |
181 | ||
182 | // Throw the comments plus a few lines about the bitstream we're | |
183 | // decoding | |
184 | { | |
185 | byte[][] ptr=vc.user_comments; | |
186 | for(int j=0; j<ptr.length;j++){ | |
187 | if(ptr[j]==null) break; | |
188 | System.err.println(new String(ptr[j], 0, ptr[j].length-1)); | |
189 | } | |
190 | System.err.println("\nBitstream is "+vi.channels+" channel, "+vi.rate+"Hz"); | |
191 | System.err.println("Encoded by: "+new String(vc.vendor, 0, vc.vendor.length-1)+"\n"); | |
192 | } | |
193 | ||
194 | convsize=4096/vi.channels; | |
195 | ||
196 | // OK, got and parsed all three headers. Initialize the Vorbis | |
197 | // packet->PCM decoder. | |
198 | vd.synthesis_init(vi); // central decode state | |
199 | vb.init(vd); // local state for most of the decode | |
200 | // so multiple block decodes can | |
201 | // proceed in parallel. We could init | |
202 | // multiple vorbis_block structures | |
203 | // for vd here | |
204 | ||
205 | float[][][] _pcm=new float[1][][]; | |
206 | int[] _index=new int[vi.channels]; | |
207 | // The rest is just a straight decode loop until end of stream | |
208 | while(eos==0){ | |
209 | while(eos==0){ | |
210 | ||
211 | int result=oy.pageout(og); | |
212 | if(result==0)break; // need more data | |
213 | if(result==-1){ // missing or corrupt data at this page position | |
214 | System.err.println("Corrupt or missing data in bitstream; continuing..."); | |
215 | } | |
216 | else{ | |
217 | os.pagein(og); // can safely ignore errors at | |
218 | // this point | |
219 | while(true){ | |
220 | result=os.packetout(op); | |
221 | ||
222 | if(result==0)break; // need more data | |
223 | if(result==-1){ // missing or corrupt data at this page position | |
224 | // no reason to complain; already complained above | |
225 | } | |
226 | else{ | |
227 | // we have a packet. Decode it | |
228 | int samples; | |
229 | if(vb.synthesis(op)==0){ // test for success! | |
230 | vd.synthesis_blockin(vb); | |
231 | } | |
232 | ||
233 | // **pcm is a multichannel float vector. In stereo, for | |
234 | // example, pcm[0] is left, and pcm[1] is right. samples is | |
235 | // the size of each channel. Convert the float values | |
236 | // (-1.<=range<=1.) to whatever PCM format and write it out | |
237 | ||
238 | while((samples=vd.synthesis_pcmout(_pcm, _index))>0){ | |
239 | float[][] pcm=_pcm[0]; | |
240 | boolean clipflag=false; | |
241 | int bout=(samples<convsize?samples:convsize); | |
242 | ||
243 | // convert floats to 16 bit signed ints (host order) and | |
244 | // interleave | |
245 | for(i=0;i<vi.channels;i++){ | |
246 | int ptr=i*2; | |
247 | //int ptr=i; | |
248 | int mono=_index[i]; | |
249 | for(int j=0;j<bout;j++){ | |
250 | int val=(int)(pcm[i][mono+j]*32767.); | |
251 | // short val=(short)(pcm[i][mono+j]*32767.); | |
252 | // int val=(int)Math.round(pcm[i][mono+j]*32767.); | |
253 | // might as well guard against clipping | |
254 | if(val>32767){ | |
255 | val=32767; | |
256 | clipflag=true; | |
257 | } | |
258 | if(val<-32768){ | |
259 | val=-32768; | |
260 | clipflag=true; | |
261 | } | |
262 | if(val<0) val=val|0x8000; | |
263 | convbuffer[ptr]=(byte)(val); | |
264 | convbuffer[ptr+1]=(byte)(val>>>8); | |
265 | ptr+=2*(vi.channels); | |
266 | } | |
267 | } | |
268 | ||
269 | //if(clipflag) | |
270 | // System.err.println("Clipping in frame "+vd.sequence); | |
271 | ||
272 | System.out.write(convbuffer, 0, 2*vi.channels*bout); | |
273 | ||
274 | vd.synthesis_read(bout); // tell libvorbis how | |
275 | // many samples we | |
276 | // actually consumed | |
277 | } | |
278 | } | |
279 | } | |
280 | if(og.eos()!=0)eos=1; | |
281 | } | |
282 | } | |
283 | if(eos==0){ | |
284 | index=oy.buffer(4096); | |
285 | buffer=oy.data; | |
286 | try{ | |
287 | bytes=input.read(buffer,index,4096); | |
288 | } | |
289 | catch(Exception e){ | |
290 | System.err.println(e); | |
291 | System.exit(1); | |
292 | } | |
293 | oy.wrote(bytes); | |
294 | if(bytes==0)eos=1; | |
295 | } | |
296 | } | |
297 | ||
298 | // clean up this logical bitstream; before exit we see if we're | |
299 | // followed by another [chained] | |
300 | ||
301 | os.clear(); | |
302 | ||
303 | // ogg_page and ogg_packet structs always point to storage in | |
304 | // libvorbis. They're never freed or manipulated directly | |
305 | ||
306 | vb.clear(); | |
307 | vd.clear(); | |
308 | vi.clear(); // must be called last | |
309 | } | |
310 | ||
311 | // OK, clean up the framer | |
312 | oy.clear(); | |
313 | System.err.println("Done."); | |
314 | } | |
315 | } | |
316 |