diff options
Diffstat (limited to 'songdbj/de/jarnbjo/ogg/OggPage.java')
-rw-r--r-- | songdbj/de/jarnbjo/ogg/OggPage.java | 431 |
1 files changed, 0 insertions, 431 deletions
diff --git a/songdbj/de/jarnbjo/ogg/OggPage.java b/songdbj/de/jarnbjo/ogg/OggPage.java deleted file mode 100644 index cc965cc7a9..0000000000 --- a/songdbj/de/jarnbjo/ogg/OggPage.java +++ /dev/null | |||
@@ -1,431 +0,0 @@ | |||
1 | /* | ||
2 | * $ProjectName$ | ||
3 | * $ProjectRevision$ | ||
4 | * ----------------------------------------------------------- | ||
5 | * $Id$ | ||
6 | * ----------------------------------------------------------- | ||
7 | * | ||
8 | * $Author$ | ||
9 | * | ||
10 | * Description: | ||
11 | * | ||
12 | * Copyright 2002-2003 Tor-Einar Jarnbjo | ||
13 | * ----------------------------------------------------------- | ||
14 | * | ||
15 | * Change History | ||
16 | * ----------------------------------------------------------- | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2005/07/11 15:42:36 hcl | ||
19 | * Songdb java version, source. only 1.5 compatible | ||
20 | * | ||
21 | * Revision 1.1.1.1 2004/04/04 22:09:12 shred | ||
22 | * First Import | ||
23 | * | ||
24 | * Revision 1.3 2003/04/10 19:48:22 jarnbjo | ||
25 | * no message | ||
26 | * | ||
27 | * Revision 1.2 2003/03/31 00:23:04 jarnbjo | ||
28 | * no message | ||
29 | * | ||
30 | * Revision 1.1 2003/03/03 21:02:20 jarnbjo | ||
31 | * no message | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | package de.jarnbjo.ogg; | ||
36 | |||
37 | import java.io.*; | ||
38 | |||
39 | import de.jarnbjo.util.io.*; | ||
40 | |||
41 | /** | ||
42 | * <p>An instance of this class represents an ogg page read from an ogg file | ||
43 | * or network stream. It has no public constructor, but instances can be | ||
44 | * created by the <code>create</code> methods, supplying a JMF stream or | ||
45 | * a <code>RandomAccessFile</code> | ||
46 | * which is positioned at the beginning of an Ogg page.</p> | ||
47 | * | ||
48 | * <p>Furtheron, the class provides methods for accessing the raw page data, | ||
49 | * as well as data attributes like segmenting information, sequence number, | ||
50 | * stream serial number, chechsum and wether this page is the beginning or | ||
51 | * end of a logical bitstream (BOS, EOS) and if the page data starts with a | ||
52 | * continued packet or a fresh data packet.</p> | ||
53 | */ | ||
54 | |||
55 | public class OggPage { | ||
56 | |||
57 | private int version; | ||
58 | private boolean continued, bos, eos; | ||
59 | private long absoluteGranulePosition; | ||
60 | private int streamSerialNumber, pageSequenceNumber, pageCheckSum; | ||
61 | private int[] segmentOffsets; | ||
62 | private int[] segmentLengths; | ||
63 | private int totalLength; | ||
64 | private byte[] header, segmentTable, data; | ||
65 | |||
66 | protected OggPage() { | ||
67 | } | ||
68 | |||
69 | private OggPage( | ||
70 | int version, | ||
71 | boolean continued, | ||
72 | boolean bos, | ||
73 | boolean eos, | ||
74 | long absoluteGranulePosition, | ||
75 | int streamSerialNumber, | ||
76 | int pageSequenceNumber, | ||
77 | int pageCheckSum, | ||
78 | int[] segmentOffsets, | ||
79 | int[] segmentLengths, | ||
80 | int totalLength, | ||
81 | byte[] header, | ||
82 | byte[] segmentTable, | ||
83 | byte[] data) { | ||
84 | |||
85 | this.version=version; | ||
86 | this.continued=continued; | ||
87 | this.bos=bos; | ||
88 | this.eos=eos; | ||
89 | this.absoluteGranulePosition=absoluteGranulePosition; | ||
90 | this.streamSerialNumber=streamSerialNumber; | ||
91 | this.pageSequenceNumber=pageSequenceNumber; | ||
92 | this.pageCheckSum=pageCheckSum; | ||
93 | this.segmentOffsets=segmentOffsets; | ||
94 | this.segmentLengths=segmentLengths; | ||
95 | this.totalLength=totalLength; | ||
96 | this.header=header; | ||
97 | this.segmentTable=segmentTable; | ||
98 | this.data=data; | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * this method equals to create(RandomAccessFile source, false) | ||
103 | * | ||
104 | * @see #create(RandomAccessFile, boolean) | ||
105 | */ | ||
106 | |||
107 | public static OggPage create(RandomAccessFile source) throws IOException, EndOfOggStreamException, OggFormatException { | ||
108 | return create(source, false); | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * This method is called to read data from the current position in the | ||
113 | * specified RandomAccessFile and create a new OggPage instance based on the data | ||
114 | * read. If the parameter <code>skipData</code> is set to <code>true</code>, | ||
115 | * the actual page segments (page data) is skipped and not read into | ||
116 | * memory. This mode is useful when scanning through an ogg file to build | ||
117 | * a seek table. | ||
118 | * | ||
119 | * @param source the source from which the ogg page is generated | ||
120 | * @param skipData if set to <code>true</code>, the actual page data is not read into memory | ||
121 | * @return an ogg page created by reading data from the specified source, starting at the current position | ||
122 | * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page | ||
123 | * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source | ||
124 | * @throws IOException if some other I/O error is detected when reading from the source | ||
125 | * | ||
126 | * @see #create(RandomAccessFile) | ||
127 | */ | ||
128 | |||
129 | public static OggPage create(RandomAccessFile source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException { | ||
130 | return create((Object)source, skipData); | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * this method equals to create(InputStream source, false) | ||
135 | * | ||
136 | * @see #create(InputStream, boolean) | ||
137 | */ | ||
138 | |||
139 | public static OggPage create(InputStream source) throws IOException, EndOfOggStreamException, OggFormatException { | ||
140 | return create(source, false); | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * This method is called to read data from the current position in the | ||
145 | * specified InpuStream and create a new OggPage instance based on the data | ||
146 | * read. If the parameter <code>skipData</code> is set to <code>true</code>, | ||
147 | * the actual page segments (page data) is skipped and not read into | ||
148 | * memory. This mode is useful when scanning through an ogg file to build | ||
149 | * a seek table. | ||
150 | * | ||
151 | * @param source the source from which the ogg page is generated | ||
152 | * @param skipData if set to <code>true</code>, the actual page data is not read into memory | ||
153 | * @return an ogg page created by reading data from the specified source, starting at the current position | ||
154 | * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page | ||
155 | * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source | ||
156 | * @throws IOException if some other I/O error is detected when reading from the source | ||
157 | * | ||
158 | * @see #create(InputStream) | ||
159 | */ | ||
160 | |||
161 | public static OggPage create(InputStream source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException { | ||
162 | return create((Object)source, skipData); | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * this method equals to create(byte[] source, false) | ||
167 | * | ||
168 | * @see #create(byte[], boolean) | ||
169 | */ | ||
170 | |||
171 | public static OggPage create(byte[] source) throws IOException, EndOfOggStreamException, OggFormatException { | ||
172 | return create(source, false); | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * This method is called to | ||
177 | * create a new OggPage instance based on the specified byte array. | ||
178 | * | ||
179 | * @param source the source from which the ogg page is generated | ||
180 | * @param skipData if set to <code>true</code>, the actual page data is not read into memory | ||
181 | * @return an ogg page created by reading data from the specified source, starting at the current position | ||
182 | * @throws FormatException if the data read from the specified source is not matching the specification for an ogg page | ||
183 | * @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source | ||
184 | * @throws IOException if some other I/O error is detected when reading from the source | ||
185 | * | ||
186 | * @see #create(byte[]) | ||
187 | */ | ||
188 | |||
189 | public static OggPage create(byte[] source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException { | ||
190 | return create((Object)source, skipData); | ||
191 | } | ||
192 | |||
193 | private static OggPage create(Object source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException { | ||
194 | |||
195 | try { | ||
196 | int sourceOffset=27; | ||
197 | |||
198 | byte[] header=new byte[27]; | ||
199 | if(source instanceof RandomAccessFile) { | ||
200 | RandomAccessFile raf=(RandomAccessFile)source; | ||
201 | if(raf.getFilePointer()==raf.length()) { | ||
202 | return null; | ||
203 | } | ||
204 | raf.readFully(header); | ||
205 | } | ||
206 | else if(source instanceof InputStream) { | ||
207 | readFully((InputStream)source, header); | ||
208 | } | ||
209 | else if(source instanceof byte[]) { | ||
210 | System.arraycopy((byte[])source, 0, header, 0, 27); | ||
211 | } | ||
212 | |||
213 | BitInputStream bdSource=new ByteArrayBitInputStream(header); | ||
214 | |||
215 | int capture=bdSource.getInt(32); | ||
216 | |||
217 | if(capture!=0x5367674f) { | ||
218 | //throw new FormatException("Ogg page does not start with 'OggS' (0x4f676753)"); | ||
219 | |||
220 | /* | ||
221 | ** This condition is IMHO an error, but older Ogg files often contain | ||
222 | ** pages with a different capture than OggS. I am not sure how to | ||
223 | ** manage these pages, but the decoder seems to work properly, if | ||
224 | ** the incorrect capture is simply ignored. | ||
225 | */ | ||
226 | |||
227 | String cs=Integer.toHexString(capture); | ||
228 | while(cs.length()<8) { | ||
229 | cs="0"+cs; | ||
230 | } | ||
231 | cs=cs.substring(6, 8)+cs.substring(4, 6)+cs.substring(2, 4)+cs.substring(0, 2); | ||
232 | char c1=(char)(Integer.valueOf(cs.substring(0, 2), 16).intValue()); | ||
233 | char c2=(char)(Integer.valueOf(cs.substring(2, 4), 16).intValue()); | ||
234 | char c3=(char)(Integer.valueOf(cs.substring(4, 6), 16).intValue()); | ||
235 | char c4=(char)(Integer.valueOf(cs.substring(6, 8), 16).intValue()); | ||
236 | System.out.println("Ogg packet header is 0x"+cs+" ("+c1+c2+c3+c4+"), should be 0x4f676753 (OggS)"); | ||
237 | } | ||
238 | |||
239 | int version=bdSource.getInt(8); | ||
240 | byte tmp=(byte)bdSource.getInt(8); | ||
241 | boolean bf1=(tmp&1)!=0; | ||
242 | boolean bos=(tmp&2)!=0; | ||
243 | boolean eos=(tmp&4)!=0; | ||
244 | long absoluteGranulePosition=bdSource.getLong(64); | ||
245 | int streamSerialNumber=bdSource.getInt(32); | ||
246 | int pageSequenceNumber=bdSource.getInt(32); | ||
247 | int pageCheckSum=bdSource.getInt(32); | ||
248 | int pageSegments=bdSource.getInt(8); | ||
249 | |||
250 | //System.out.println("OggPage: "+streamSerialNumber+" / "+absoluteGranulePosition+" / "+pageSequenceNumber); | ||
251 | |||
252 | int[] segmentOffsets=new int[pageSegments]; | ||
253 | int[] segmentLengths=new int[pageSegments]; | ||
254 | int totalLength=0; | ||
255 | |||
256 | byte[] segmentTable=new byte[pageSegments]; | ||
257 | byte[] tmpBuf=new byte[1]; | ||
258 | |||
259 | for(int i=0; i<pageSegments; i++) { | ||
260 | int l=0; | ||
261 | if(source instanceof RandomAccessFile) { | ||
262 | l=((int)((RandomAccessFile)source).readByte()&0xff); | ||
263 | } | ||
264 | else if(source instanceof InputStream) { | ||
265 | l=(int)((InputStream)source).read(); | ||
266 | } | ||
267 | else if(source instanceof byte[]) { | ||
268 | l=(int)((byte[])source)[sourceOffset++]; | ||
269 | l&=255; | ||
270 | } | ||
271 | segmentTable[i]=(byte)l; | ||
272 | segmentLengths[i]=l; | ||
273 | segmentOffsets[i]=totalLength; | ||
274 | totalLength+=l; | ||
275 | } | ||
276 | |||
277 | byte[] data=null; | ||
278 | |||
279 | if(!skipData) { | ||
280 | |||
281 | //System.out.println("createPage: "+absoluteGranulePosition*1000/44100); | ||
282 | |||
283 | data=new byte[totalLength]; | ||
284 | //source.read(data, 0, totalLength); | ||
285 | if(source instanceof RandomAccessFile) { | ||
286 | ((RandomAccessFile)source).readFully(data); | ||
287 | } | ||
288 | else if(source instanceof InputStream) { | ||
289 | readFully((InputStream)source, data); | ||
290 | } | ||
291 | else if(source instanceof byte[]) { | ||
292 | System.arraycopy(source, sourceOffset, data, 0, totalLength); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | return new OggPage(version, bf1, bos, eos, absoluteGranulePosition, streamSerialNumber, pageSequenceNumber, pageCheckSum, segmentOffsets, segmentLengths, totalLength, header, segmentTable, data); | ||
297 | } | ||
298 | catch(EOFException e) { | ||
299 | throw new EndOfOggStreamException(); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | private static void readFully(InputStream source, byte[] buffer) throws IOException { | ||
304 | int total=0; | ||
305 | while(total<buffer.length) { | ||
306 | int read=source.read(buffer, total, buffer.length-total); | ||
307 | if(read==-1) { | ||
308 | throw new EndOfOggStreamException(); | ||
309 | } | ||
310 | total+=read; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * Returns the absolute granule position of the last complete | ||
316 | * packet contained in this Ogg page, or -1 if the page contains a single | ||
317 | * packet, which is not completed on this page. For pages containing Vorbis | ||
318 | * data, this value is the sample index within the Vorbis stream. The Vorbis | ||
319 | * stream does not necessarily start with sample index 0. | ||
320 | * | ||
321 | * @return the absolute granule position of the last packet completed on | ||
322 | * this page | ||
323 | */ | ||
324 | |||
325 | |||
326 | public long getAbsoluteGranulePosition() { | ||
327 | return absoluteGranulePosition; | ||
328 | } | ||
329 | |||
330 | /** | ||
331 | * Returns the stream serial number of this ogg page. | ||
332 | * | ||
333 | * @return this page's serial number | ||
334 | */ | ||
335 | |||
336 | public int getStreamSerialNumber() { | ||
337 | return streamSerialNumber; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * Return the sequnce number of this ogg page. | ||
342 | * | ||
343 | * @return this page's sequence number | ||
344 | */ | ||
345 | |||
346 | public int getPageSequenceNumber() { | ||
347 | return pageSequenceNumber; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * Return the check sum of this ogg page. | ||
352 | * | ||
353 | * @return this page's check sum | ||
354 | */ | ||
355 | |||
356 | public int getPageCheckSum() { | ||
357 | return pageCheckSum; | ||
358 | } | ||
359 | |||
360 | /** | ||
361 | * @return the total number of bytes in the page data | ||
362 | */ | ||
363 | |||
364 | |||
365 | public int getTotalLength() { | ||
366 | if(data!=null) { | ||
367 | return 27+segmentTable.length+data.length; | ||
368 | } | ||
369 | else { | ||
370 | return totalLength; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | /** | ||
375 | * @return a ByteBuffer containing the page data | ||
376 | */ | ||
377 | |||
378 | |||
379 | public byte[] getData() { | ||
380 | return data; | ||
381 | } | ||
382 | |||
383 | public byte[] getHeader() { | ||
384 | return header; | ||
385 | } | ||
386 | |||
387 | public byte[] getSegmentTable() { | ||
388 | return segmentTable; | ||
389 | } | ||
390 | |||
391 | public int[] getSegmentOffsets() { | ||
392 | return segmentOffsets; | ||
393 | } | ||
394 | |||
395 | public int[] getSegmentLengths() { | ||
396 | return segmentLengths; | ||
397 | } | ||
398 | |||
399 | /** | ||
400 | * @return <code>true</code> if this page begins with a continued packet | ||
401 | */ | ||
402 | |||
403 | public boolean isContinued() { | ||
404 | return continued; | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * @return <code>true</code> if this page begins with a fresh packet | ||
409 | */ | ||
410 | |||
411 | public boolean isFresh() { | ||
412 | return !continued; | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * @return <code>true</code> if this page is the beginning of a logical stream | ||
417 | */ | ||
418 | |||
419 | public boolean isBos() { | ||
420 | return bos; | ||
421 | } | ||
422 | |||
423 | /** | ||
424 | * @return <code>true</code> if this page is the end of a logical stream | ||
425 | */ | ||
426 | |||
427 | public boolean isEos() { | ||
428 | return eos; | ||
429 | } | ||
430 | |||
431 | } \ No newline at end of file | ||