2 * 11/19/04 1.0 moved to LGPL.
\r
4 * 11/17/04 Uncomplete frames discarded. E.B, javalayer@javazoom.net
\r
6 * 12/05/03 ID3v2 tag returned. E.B, javalayer@javazoom.net
\r
8 * 12/12/99 Based on Ibitstream. Exceptions thrown on errors,
\r
9 * Temporary removed seek functionality. mdm@techie.com
\r
11 * 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net
\r
13 * 04/14/97 : Added function prototypes for new syncing and seeking
\r
14 * mechanisms. Also made this file portable. Changes made by Jeff Tsay
\r
16 * @(#) ibitstream.h 1.5, last edit: 6/15/94 16:55:34
\r
17 * @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
\r
18 * @(#) Berlin University of Technology
\r
19 *-----------------------------------------------------------------------
\r
20 * This program is free software; you can redistribute it and/or modify
\r
21 * it under the terms of the GNU Library General Public License as published
\r
22 * by the Free Software Foundation; either version 2 of the License, or
\r
23 * (at your option) any later version.
\r
25 * This program is distributed in the hope that it will be useful,
\r
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
28 * GNU Library General Public License for more details.
\r
30 * You should have received a copy of the GNU Library General Public
\r
31 * License along with this program; if not, write to the Free Software
\r
32 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
33 *----------------------------------------------------------------------
\r
38 * The <code>Bistream</code> class is responsible for parsing
\r
39 * an MPEG audio bitstream.
\r
41 * <b>REVIEW:</b> much of the parsing currently occurs in the
\r
42 * various decoders. This should be moved into this class and associated
\r
45 public final class Bitstream implements BitstreamErrors
\r
48 * Synchronization control constant for the initial
\r
49 * synchronization to the start of a frame.
\r
51 static final byte INITIAL_SYNC = 0;
\r
54 * Synchronization control constant for non-initial frame
\r
57 static final byte STRICT_SYNC = 1;
\r
59 // max. 1730 bytes per frame: 144 * 384kbit/s / 32000 Hz + 2 Bytes CRC
\r
61 * Maximum size of the frame buffer.
\r
63 private static final int BUFFER_INT_SIZE = 433;
\r
66 * The frame buffer that holds the data for the current frame.
\r
68 private final int[] framebuffer = new int[BUFFER_INT_SIZE];
\r
71 * Number of valid bytes in the frame buffer.
\r
73 private int framesize;
\r
76 * The bytes read from the stream.
\r
78 private byte[] frame_bytes = new byte[BUFFER_INT_SIZE*4];
\r
81 * Index into <code>framebuffer</code> where the next bits are
\r
84 private int wordpointer;
\r
87 * Number (0-31, from MSB to LSB) of next bit for get_bits()
\r
89 private int bitindex;
\r
92 * The current specified syncword
\r
94 private int syncword;
\r
97 * Audio header position in stream.
\r
99 private int header_pos = 0;
\r
104 private boolean single_ch_mode;
\r
105 //private int current_frame_number;
\r
106 //private int last_frame_number;
\r
108 private final int bitmask[] = {0, // dummy
\r
109 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
\r
110 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
\r
111 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
\r
112 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
\r
115 private final PushbackInputStream source;
\r
117 private final Header header = new Header();
\r
119 private final byte syncbuf[] = new byte[4];
\r
121 private Crc16[] crc = new Crc16[1];
\r
123 private byte[] rawid3v2 = null;
\r
125 private boolean firstframe = true;
\r
129 * Construct a IBitstream that reads data from a
\r
130 * given InputStream.
\r
132 * @param in The InputStream to read from.
\r
134 public Bitstream(InputStream in)
\r
136 if (in==null) throw new NullPointerException("in");
\r
137 in = new BufferedInputStream(in);
\r
140 //source = new PushbackInputStream(in, 1024);
\r
141 source = new PushbackInputStream(in, BUFFER_INT_SIZE*4);
\r
144 //current_frame_number = -1;
\r
145 //last_frame_number = -1;
\r
149 * Return position of the first audio header.
\r
150 * @return size of ID3v2 tag frames.
\r
152 public int header_pos()
\r
158 * Load ID3v2 frames.
\r
159 * @param in MP3 InputStream.
\r
162 private void loadID3v2(InputStream in)
\r
167 // Read ID3v2 header (10 bytes).
\r
169 size = readID3v2Header(in);
\r
170 header_pos = size;
\r
172 catch (IOException e)
\r
178 // Unread ID3v2 header (10 bytes).
\r
181 catch (IOException e)
\r
184 // Load ID3v2 tags.
\r
189 rawid3v2 = new byte[size];
\r
190 in.read(rawid3v2,0,rawid3v2.length);
\r
193 catch (IOException e)
\r
198 * Parse ID3v2 tag header to find out size of ID3v2 frames.
\r
199 * @param in MP3 InputStream
\r
200 * @return size of ID3v2 frames + header
\r
201 * @throws IOException
\r
204 private int readID3v2Header(InputStream in) throws IOException
\r
206 byte[] id3header = new byte[4];
\r
208 in.read(id3header,0,3);
\r
210 if ( (id3header[0]=='I') && (id3header[1]=='D') && (id3header[2]=='3'))
\r
212 in.read(id3header,0,3);
\r
213 int majorVersion = id3header[0];
\r
214 int revision = id3header[1];
\r
215 in.read(id3header,0,4);
\r
216 size = (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]);
\r
222 * Return raw ID3v2 frames + header.
\r
223 * @return ID3v2 InputStream or null if ID3v2 frames are not available.
\r
225 public InputStream getRawID3v2()
\r
227 if (rawid3v2 == null) return null;
\r
230 ByteArrayInputStream bain = new ByteArrayInputStream(rawid3v2);
\r
236 * Close the Bitstream.
\r
237 * @throws BitstreamException
\r
239 public void close() throws BitstreamException
\r
245 catch (IOException ex)
\r
247 throw newBitstreamException(STREAM_ERROR, ex);
\r
252 * Reads and parses the next frame from the input source.
\r
253 * @return the Header describing details of the frame read,
\r
254 * or null if the end of the stream has been reached.
\r
256 public Header readFrame() throws BitstreamException
\r
258 Header result = null;
\r
261 result = readNextFrame();
\r
262 // E.B, Parse VBR (if any) first frame.
\r
263 if (firstframe == true)
\r
265 result.parseVBR(frame_bytes);
\r
266 firstframe = false;
\r
269 catch (BitstreamException ex)
\r
271 if ((ex.getErrorCode()==INVALIDFRAME))
\r
273 // Try to skip this frame.
\r
274 //System.out.println("INVALIDFRAME");
\r
278 result = readNextFrame();
\r
280 catch (BitstreamException e)
\r
282 if ((e.getErrorCode()!=STREAM_EOF))
\r
284 // wrap original exception so stack trace is maintained.
\r
285 throw newBitstreamException(e.getErrorCode(), e);
\r
289 else if ((ex.getErrorCode()!=STREAM_EOF))
\r
291 // wrap original exception so stack trace is maintained.
\r
292 throw newBitstreamException(ex.getErrorCode(), ex);
\r
299 * Read next MP3 frame.
\r
300 * @return MP3 frame header.
\r
301 * @throws BitstreamException
\r
303 private Header readNextFrame() throws BitstreamException
\r
305 if (framesize == -1)
\r
314 * Read next MP3 frame.
\r
315 * @throws BitstreamException
\r
317 private void nextFrame() throws BitstreamException
\r
319 // entire frame is read by the header class.
\r
320 header.read_header(this, crc);
\r
324 * Unreads the bytes read from the frame.
\r
325 * @throws BitstreamException
\r
327 // REVIEW: add new error codes for this.
\r
328 public void unreadFrame() throws BitstreamException
\r
330 if (wordpointer==-1 && bitindex==-1 && (framesize>0))
\r
334 source.unread(frame_bytes, 0, framesize);
\r
336 catch (IOException ex)
\r
338 throw newBitstreamException(STREAM_ERROR);
\r
346 public void closeFrame()
\r
354 * Determines if the next 4 bytes of the stream represent a
\r
357 public boolean isSyncCurrentPosition(int syncmode) throws BitstreamException
\r
359 int read = readBytes(syncbuf, 0, 4);
\r
360 int headerstring = ((syncbuf[0] << 24) & 0xFF000000) | ((syncbuf[1] << 16) & 0x00FF0000) | ((syncbuf[2] << 8) & 0x0000FF00) | ((syncbuf[3] << 0) & 0x000000FF);
\r
364 source.unread(syncbuf, 0, read);
\r
366 catch (IOException ex)
\r
370 boolean sync = false;
\r
377 sync = isSyncMark(headerstring, syncmode, syncword);
\r
385 // REVIEW: this class should provide inner classes to
\r
386 // parse the frame contents. Eventually, readBits will
\r
388 public int readBits(int n)
\r
390 return get_bits(n);
\r
393 public int readCheckedBits(int n)
\r
395 // REVIEW: implement CRC check.
\r
396 return get_bits(n);
\r
399 protected BitstreamException newBitstreamException(int errorcode)
\r
401 return new BitstreamException(errorcode, null);
\r
403 protected BitstreamException newBitstreamException(int errorcode, Throwable throwable)
\r
405 return new BitstreamException(errorcode, throwable);
\r
409 * Get next 32 bits from bitstream.
\r
410 * They are stored in the headerstring.
\r
411 * syncmod allows Synchro flag ID
\r
412 * The returned value is False at the end of stream.
\r
415 int syncHeader(byte syncmode) throws BitstreamException
\r
419 // read additional 2 bytes
\r
420 int bytesRead = readBytes(syncbuf, 0, 3);
\r
422 if (bytesRead!=3) throw newBitstreamException(STREAM_EOF, null);
\r
424 headerstring = ((syncbuf[0] << 16) & 0x00FF0000) | ((syncbuf[1] << 8) & 0x0000FF00) | ((syncbuf[2] << 0) & 0x000000FF);
\r
428 headerstring <<= 8;
\r
430 if (readBytes(syncbuf, 3, 1)!=1)
\r
431 throw newBitstreamException(STREAM_EOF, null);
\r
433 headerstring |= (syncbuf[3] & 0x000000FF);
\r
435 sync = isSyncMark(headerstring, syncmode, syncword);
\r
439 //current_frame_number++;
\r
440 //if (last_frame_number < current_frame_number) last_frame_number = current_frame_number;
\r
442 return headerstring;
\r
445 public boolean isSyncMark(int headerstring, int syncmode, int word)
\r
447 boolean sync = false;
\r
449 if (syncmode == INITIAL_SYNC)
\r
451 //sync = ((headerstring & 0xFFF00000) == 0xFFF00000);
\r
452 sync = ((headerstring & 0xFFE00000) == 0xFFE00000); // SZD: MPEG 2.5
\r
456 sync = ((headerstring & 0xFFF80C00) == word) &&
\r
457 (((headerstring & 0x000000C0) == 0x000000C0) == single_ch_mode);
\r
460 // filter out invalid sample rate
\r
462 sync = (((headerstring >>> 10) & 3)!=3);
\r
463 // filter out invalid layer
\r
465 sync = (((headerstring >>> 17) & 3)!=0);
\r
466 // filter out invalid version
\r
468 sync = (((headerstring >>> 19) & 3)!=1);
\r
474 * Reads the data for the next frame. The frame is not parsed
\r
475 * until parse frame is called.
\r
477 int read_frame_data(int bytesize) throws BitstreamException
\r
480 numread = readFully(frame_bytes, 0, bytesize);
\r
481 framesize = bytesize;
\r
488 * Parses the data previously read with read_frame_data().
\r
490 void parse_frame() throws BitstreamException
\r
492 // Convert Bytes read to int
\r
494 byte[] byteread = frame_bytes;
\r
495 int bytesize = framesize;
\r
497 // Check ID3v1 TAG (True only if last frame).
\r
498 //for (int t=0;t<(byteread.length)-2;t++)
\r
500 // if ((byteread[t]=='T') && (byteread[t+1]=='A') && (byteread[t+2]=='G'))
\r
502 // System.out.println("ID3v1 detected at offset "+t);
\r
503 // throw newBitstreamException(INVALIDFRAME, null);
\r
507 for (int k=0;k<bytesize;k=k+4)
\r
515 if (k+1<bytesize) b1 = byteread[k+1];
\r
516 if (k+2<bytesize) b2 = byteread[k+2];
\r
517 if (k+3<bytesize) b3 = byteread[k+3];
\r
518 framebuffer[b++] = ((b0 << 24) &0xFF000000) | ((b1 << 16) & 0x00FF0000) | ((b2 << 8) & 0x0000FF00) | (b3 & 0x000000FF);
\r
525 * Read bits from buffer into the lower bits of an unsigned int.
\r
526 * The LSB contains the latest read bit of the stream.
\r
527 * (1 <= number_of_bits <= 16)
\r
529 public int get_bits(int number_of_bits)
\r
531 int returnvalue = 0;
\r
532 int sum = bitindex + number_of_bits;
\r
535 // There is a problem here, wordpointer could be -1 ?!
\r
536 if (wordpointer < 0) wordpointer = 0;
\r
541 // all bits contained in *wordpointer
\r
542 returnvalue = (framebuffer[wordpointer] >>> (32 - sum)) & bitmask[number_of_bits];
\r
543 // returnvalue = (wordpointer[0] >> (32 - sum)) & bitmask[number_of_bits];
\r
544 if ((bitindex += number_of_bits) == 32)
\r
547 wordpointer++; // added by me!
\r
549 return returnvalue;
\r
552 // E.B : Check that ?
\r
553 //((short[])&returnvalue)[0] = ((short[])wordpointer + 1)[0];
\r
554 //wordpointer++; // Added by me!
\r
555 //((short[])&returnvalue + 1)[0] = ((short[])wordpointer)[0];
\r
556 int Right = (framebuffer[wordpointer] & 0x0000FFFF);
\r
558 int Left = (framebuffer[wordpointer] & 0xFFFF0000);
\r
559 returnvalue = ((Right << 16) & 0xFFFF0000) | ((Left >>> 16)& 0x0000FFFF);
\r
561 returnvalue >>>= 48 - sum; // returnvalue >>= 16 - (number_of_bits - (32 - bitindex))
\r
562 returnvalue &= bitmask[number_of_bits];
\r
563 bitindex = sum - 32;
\r
564 return returnvalue;
\r
568 * Set the word we want to sync the header to.
\r
569 * In Big-Endian byte order
\r
571 void set_syncword(int syncword0)
\r
573 syncword = syncword0 & 0xFFFFFF3F;
\r
574 single_ch_mode = ((syncword0 & 0x000000C0) == 0x000000C0);
\r
577 * Reads the exact number of bytes from the source
\r
578 * input stream into a byte array.
\r
580 * @param b The byte array to read the specified number
\r
582 * @param offs The index in the array where the first byte
\r
583 * read should be stored.
\r
584 * @param len the number of bytes to read.
\r
586 * @exception BitstreamException is thrown if the specified
\r
587 * number of bytes could not be read from the stream.
\r
589 private int readFully(byte[] b, int offs, int len)
\r
590 throws BitstreamException
\r
597 int bytesread = source.read(b, offs, len);
\r
598 if (bytesread == -1)
\r
605 //throw newBitstreamException(UNEXPECTED_EOF, new EOFException());
\r
607 nRead = nRead + bytesread;
\r
612 catch (IOException ex)
\r
614 throw newBitstreamException(STREAM_ERROR, ex);
\r
620 * Simlar to readFully, but doesn't throw exception when
\r
623 private int readBytes(byte[] b, int offs, int len)
\r
624 throws BitstreamException
\r
626 int totalBytesRead = 0;
\r
631 int bytesread = source.read(b, offs, len);
\r
632 if (bytesread == -1)
\r
636 totalBytesRead += bytesread;
\r
641 catch (IOException ex)
\r
643 throw newBitstreamException(STREAM_ERROR, ex);
\r
645 return totalBytesRead;
\r