get rid of the stream parsing that occurs in the Layer III decoder. BitStream.readFra...
[IRC.git] / Robust / src / Tests / ssJava / mp3decoder / Bitstream.java
index 7fd9be8..daf25e2 100644 (file)
-/*\r
- * 11/19/04  1.0 moved to LGPL.\r
- * \r
- * 11/17/04     Uncomplete frames discarded. E.B, javalayer@javazoom.net \r
- *\r
- * 12/05/03     ID3v2 tag returned. E.B, javalayer@javazoom.net \r
- *\r
- * 12/12/99     Based on Ibitstream. Exceptions thrown on errors,\r
- *                      Temporary removed seek functionality. mdm@techie.com\r
- *\r
- * 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net\r
- *\r
- * 04/14/97 : Added function prototypes for new syncing and seeking\r
- * mechanisms. Also made this file portable. Changes made by Jeff Tsay\r
- *\r
- *  @(#) ibitstream.h 1.5, last edit: 6/15/94 16:55:34\r
- *  @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)\r
- *  @(#) Berlin University of Technology\r
- *-----------------------------------------------------------------------\r
- *   This program is free software; you can redistribute it and/or modify\r
- *   it under the terms of the GNU Library General Public License as published\r
- *   by the Free Software Foundation; either version 2 of the License, or\r
- *   (at your option) any later version.\r
- *\r
- *   This program is distributed in the hope that it will be useful,\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *   GNU Library General Public License for more details.\r
- *\r
- *   You should have received a copy of the GNU Library General Public\r
- *   License along with this program; if not, write to the Free Software\r
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- *----------------------------------------------------------------------\r
- */\r
-\r
-\r
-/**\r
- * The <code>Bistream</code> class is responsible for parsing\r
- * an MPEG audio bitstream.\r
- *\r
- * <b>REVIEW:</b> much of the parsing currently occurs in the\r
- * various decoders. This should be moved into this class and associated\r
- * inner classes.\r
- */\r
-public final class Bitstream implements BitstreamErrors\r
-{\r
-       /**\r
-        * Synchronization control constant for the initial\r
-        * synchronization to the start of a frame.\r
-        */\r
-       static byte             INITIAL_SYNC = 0;\r
-\r
-       /**\r
-        * Synchronization control constant for non-initial frame\r
-        * synchronizations.\r
-        */\r
-       static byte             STRICT_SYNC = 1;\r
-\r
-       // max. 1730 bytes per frame: 144 * 384kbit/s / 32000 Hz + 2 Bytes CRC\r
-       /**\r
-        * Maximum size of the frame buffer.\r
-        */\r
-       private static final int        BUFFER_INT_SIZE = 433;\r
-\r
-       /**\r
-        * The frame buffer that holds the data for the current frame.\r
-        */\r
-       private final int[]             framebuffer = new int[BUFFER_INT_SIZE];\r
-\r
-       /**\r
-        * Number of valid bytes in the frame buffer.\r
-        */\r
-       private int                             framesize;\r
-\r
-       /**\r
-        * The bytes read from the stream.\r
-        */\r
-       private byte[]                  frame_bytes = new byte[BUFFER_INT_SIZE*4];\r
-\r
-       /**\r
-        * Index into <code>framebuffer</code> where the next bits are\r
-        * retrieved.\r
-        */\r
-       private int                             wordpointer;\r
-\r
-       /**\r
-        * Number (0-31, from MSB to LSB) of next bit for get_bits()\r
-        */\r
-       private int                             bitindex;\r
-\r
-       /**\r
-        * The current specified syncword\r
-        */\r
-       private int                             syncword;\r
-       \r
-       /**\r
-        * Audio header position in stream.\r
-        */\r
-       private int                             header_pos = 0;\r
-\r
-       /**\r
-        *\r
-        */\r
-       private boolean                 single_ch_mode;\r
-  //private int                        current_frame_number;\r
-  //private int                                last_frame_number;\r
-\r
-       private final int               bitmask[] = {0, // dummy\r
-        0x00000001, 0x00000003, 0x00000007, 0x0000000F,\r
-        0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,\r
-        0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,\r
-        0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,\r
-     0x0001FFFF };\r
-\r
-       private final PushbackInputStream       source;\r
-\r
-       private final Header                    header = new Header();\r
-\r
-       private final byte                              syncbuf[] = new byte[4];\r
-\r
-       private Crc16[]                                 crc = new Crc16[1];\r
-\r
-       private byte[]                                  rawid3v2 = null;\r
-\r
-       private boolean                                 firstframe = true;\r
-\r
-\r
-       /**\r
-        * Construct a IBitstream that reads data from a\r
-        * given InputStream.\r
-        *\r
-        * @param in    The InputStream to read from.\r
-        */\r
-       public Bitstream(InputStream in)\r
-       {\r
-               if (in==null) throw new NullPointerException("in");\r
-               in = new BufferedInputStream(in);               \r
-               loadID3v2(in);\r
-               firstframe = true;\r
-               //source = new PushbackInputStream(in, 1024);\r
-               source = new PushbackInputStream(in, BUFFER_INT_SIZE*4);\r
-               \r
-               closeFrame();\r
-               //current_frame_number = -1;\r
-               //last_frame_number = -1;\r
-       }\r
-\r
-       /**\r
-        * Return position of the first audio header.\r
-        * @return size of ID3v2 tag frames.\r
-        */\r
-       public int header_pos()\r
-       {\r
-               return header_pos;\r
-       }\r
-       \r
-       /**\r
-        * Load ID3v2 frames.\r
-        * @param in MP3 InputStream.\r
-        * @author JavaZOOM\r
-        */\r
-       private void loadID3v2(InputStream in)\r
-       {               \r
-               int size = -1;\r
-               try\r
-               {\r
-                       // Read ID3v2 header (10 bytes).\r
-                       in.mark(10);                    \r
-                       size = readID3v2Header(in);\r
-                       header_pos = size;                      \r
-               }\r
-               catch (IOException e)\r
-               {}\r
-               finally\r
-               {\r
-                       try\r
-                       {\r
-                               // Unread ID3v2 header (10 bytes).\r
-                               in.reset();\r
-                       }\r
-                       catch (IOException e)\r
-                       {}\r
-               }\r
-               // Load ID3v2 tags.\r
-               try\r
-               {\r
-                       if (size > 0)\r
-                       {\r
-                               rawid3v2 = new byte[size];\r
-                               in.read(rawid3v2,0,rawid3v2.length);\r
-                       }                       \r
-               }\r
-               catch (IOException e)\r
-               {}\r
-       }\r
-       \r
-       /**\r
-        * Parse ID3v2 tag header to find out size of ID3v2 frames. \r
-        * @param in MP3 InputStream\r
-        * @return size of ID3v2 frames + header\r
-        * @throws IOException\r
-        * @author JavaZOOM\r
-        */\r
-       private int readID3v2Header(InputStream in) throws IOException\r
-       {               \r
-               byte[] id3header = new byte[4];\r
-               int size = -10;\r
-               in.read(id3header,0,3);\r
-               // Look for ID3v2\r
-               if ( (id3header[0]=='I') && (id3header[1]=='D') && (id3header[2]=='3'))\r
-               {\r
-                       in.read(id3header,0,3);\r
-                       int majorVersion = id3header[0];\r
-                       int revision = id3header[1];\r
-                       in.read(id3header,0,4);\r
-                       size = (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]);\r
-               }\r
-               return (size+10);\r
-       }\r
-       \r
-       /**\r
-        * Return raw ID3v2 frames + header.\r
-        * @return ID3v2 InputStream or null if ID3v2 frames are not available.\r
-        */\r
-       public InputStream getRawID3v2()\r
-       {\r
-               if (rawid3v2 == null) return null;\r
-               else\r
-               {\r
-                       ByteArrayInputStream bain = new ByteArrayInputStream(rawid3v2);         \r
-                       return bain;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Close the Bitstream.\r
-        * @throws BitstreamException\r
-        */\r
-       public void close() throws BitstreamException\r
-       {\r
-               try\r
-               {\r
-                       source.close();\r
-               }\r
-               catch (IOException ex)\r
-               {\r
-                       throw newBitstreamException(STREAM_ERROR, ex);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Reads and parses the next frame from the input source.\r
-        * @return the Header describing details of the frame read,\r
-        *      or null if the end of the stream has been reached.\r
-        */\r
-       public Header readFrame() throws BitstreamException\r
-       {\r
-               Header result = null;\r
-               try\r
-               {\r
-                       result = readNextFrame();\r
-                       // E.B, Parse VBR (if any) first frame.\r
-                       if (firstframe == true)\r
-                       {\r
-                               result.parseVBR(frame_bytes);\r
-                               firstframe = false;\r
-                       }                       \r
-               }\r
-               catch (BitstreamException ex)\r
-               {\r
-                       if ((ex.getErrorCode()==INVALIDFRAME))\r
-                       {\r
-                               // Try to skip this frame.\r
-                               //System.out.println("INVALIDFRAME");\r
-                               try\r
-                               {\r
-                                       closeFrame();\r
-                                       result = readNextFrame();\r
-                               }\r
-                               catch (BitstreamException e)\r
-                               {\r
-                                       if ((e.getErrorCode()!=STREAM_EOF))\r
-                                       {\r
-                                               // wrap original exception so stack trace is maintained.\r
-                                               throw newBitstreamException(e.getErrorCode(), e);\r
-                                       }\r
-                               }\r
-                       }\r
-                       else if ((ex.getErrorCode()!=STREAM_EOF))\r
-                       {\r
-                               // wrap original exception so stack trace is maintained.\r
-                               throw newBitstreamException(ex.getErrorCode(), ex);\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-\r
-       /**\r
-        * Read next MP3 frame.\r
-        * @return MP3 frame header.\r
-        * @throws BitstreamException\r
-        */\r
-       private Header readNextFrame() throws BitstreamException\r
-       {\r
-               if (framesize == -1)\r
-               {\r
-                       nextFrame();\r
-               }\r
-               return header;\r
-       }\r
-\r
-\r
-       /**\r
-        * Read next MP3 frame.\r
-        * @throws BitstreamException\r
-        */\r
-       private void nextFrame() throws BitstreamException\r
-       {\r
-               // entire frame is read by the header class.\r
-               header.read_header(this, crc);\r
-       }\r
-\r
-       /**\r
-        * Unreads the bytes read from the frame.\r
-        * @throws BitstreamException\r
-        */\r
-       // REVIEW: add new error codes for this.\r
-       public void unreadFrame() throws BitstreamException\r
-       {\r
-               if (wordpointer==-1 && bitindex==-1 && (framesize>0))\r
-               {\r
-                       try\r
-                       {\r
-                               source.unread(frame_bytes, 0, framesize);\r
-                       }\r
-                       catch (IOException ex)\r
-                       {\r
-                               throw newBitstreamException(STREAM_ERROR);\r
-                       }\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Close MP3 frame.\r
-        */\r
-       public void closeFrame()\r
-       {\r
-               framesize = -1;\r
-               wordpointer = -1;\r
-               bitindex = -1;\r
-       }\r
-\r
-       /**\r
-        * Determines if the next 4 bytes of the stream represent a\r
-        * frame header.\r
-        */\r
-       public boolean isSyncCurrentPosition(int syncmode) throws BitstreamException\r
-       {\r
-               int read = readBytes(syncbuf, 0, 4);\r
-               int headerstring = ((syncbuf[0] << 24) & 0xFF000000) | ((syncbuf[1] << 16) & 0x00FF0000) | ((syncbuf[2] << 8) & 0x0000FF00) | ((syncbuf[3] << 0) & 0x000000FF);\r
-\r
-               try\r
-               {\r
-                       source.unread(syncbuf, 0, read);\r
-               }\r
-               catch (IOException ex)\r
-               {\r
-               }\r
-\r
-               boolean sync = false;\r
-               switch (read)\r
-               {\r
-                       case 0:\r
-                               sync = true;\r
-                               break;\r
-                       case 4:\r
-                               sync = isSyncMark(headerstring, syncmode, syncword);\r
-                               break;\r
-               }\r
-\r
-               return sync;\r
-       }\r
-\r
-\r
-       // REVIEW: this class should provide inner classes to\r
-       // parse the frame contents. Eventually, readBits will\r
-       // be removed.\r
-       public int readBits(int n)\r
-       {\r
-               return get_bits(n);\r
-       }\r
-\r
-       public int readCheckedBits(int n)\r
-       {\r
-               // REVIEW: implement CRC check.\r
-               return get_bits(n);\r
-       }\r
-\r
-       protected BitstreamException newBitstreamException(int errorcode)\r
-       {\r
-               return new BitstreamException(errorcode, null);\r
-       }\r
-       protected BitstreamException newBitstreamException(int errorcode, Throwable throwable)\r
-       {\r
-               return new BitstreamException(errorcode, throwable);\r
-       }\r
-\r
-  /**\r
-   * Get next 32 bits from bitstream.\r
-   * They are stored in the headerstring.\r
-   * syncmod allows Synchro flag ID\r
-   * The returned value is False at the end of stream.\r
-   */\r
-\r
-       int syncHeader(byte syncmode) throws BitstreamException\r
-       {\r
-               boolean sync;\r
-               int headerstring;\r
-               // read additional 2 bytes\r
-               int bytesRead = readBytes(syncbuf, 0, 3);\r
-\r
-               if (bytesRead!=3) throw newBitstreamException(STREAM_EOF, null);\r
-\r
-               headerstring = ((syncbuf[0] << 16) & 0x00FF0000) | ((syncbuf[1] << 8) & 0x0000FF00) | ((syncbuf[2] << 0) & 0x000000FF);\r
-\r
-               do\r
-               {\r
-                       headerstring <<= 8;\r
-\r
-                       if (readBytes(syncbuf, 3, 1)!=1)\r
-                               throw newBitstreamException(STREAM_EOF, null);\r
-\r
-                       headerstring |= (syncbuf[3] & 0x000000FF);\r
-\r
-                       sync = isSyncMark(headerstring, syncmode, syncword);\r
-               }\r
-               while (!sync);\r
-\r
-               //current_frame_number++;\r
-               //if (last_frame_number < current_frame_number) last_frame_number = current_frame_number;\r
-\r
-               return headerstring;\r
-       }\r
-\r
-       public boolean isSyncMark(int headerstring, int syncmode, int word)\r
-       {\r
-               boolean sync = false;\r
-\r
-               if (syncmode == INITIAL_SYNC)\r
-               {\r
-                       //sync =  ((headerstring & 0xFFF00000) == 0xFFF00000);\r
-                       sync =  ((headerstring & 0xFFE00000) == 0xFFE00000);    // SZD: MPEG 2.5\r
-               }\r
-               else\r
-               {\r
-                       sync =  ((headerstring & 0xFFF80C00) == word) &&\r
-                           (((headerstring & 0x000000C0) == 0x000000C0) == single_ch_mode);\r
-               }\r
-\r
-               // filter out invalid sample rate\r
-               if (sync)\r
-                       sync = (((headerstring >>> 10) & 3)!=3);\r
-               // filter out invalid layer\r
-               if (sync)\r
-                       sync = (((headerstring >>> 17) & 3)!=0);\r
-               // filter out invalid version\r
-               if (sync)\r
-                       sync = (((headerstring >>> 19) & 3)!=1);\r
-\r
-               return sync;\r
-       }\r
-\r
-       /**\r
-        * Reads the data for the next frame. The frame is not parsed\r
-        * until parse frame is called.\r
-        */\r
-       int read_frame_data(int bytesize) throws BitstreamException\r
-       {\r
-               int     numread = 0;\r
-               numread = readFully(frame_bytes, 0, bytesize);\r
-               framesize = bytesize;\r
-               wordpointer = -1;\r
-           bitindex = -1;\r
-           return numread;\r
-       }\r
-\r
-  /**\r
-   * Parses the data previously read with read_frame_data().\r
-   */\r
-  void parse_frame() throws BitstreamException\r
-  {\r
-       // Convert Bytes read to int\r
-       int     b=0;\r
-       byte[] byteread = frame_bytes;\r
-       int bytesize = framesize;\r
-\r
-       // Check ID3v1 TAG (True only if last frame).\r
-       //for (int t=0;t<(byteread.length)-2;t++)\r
-       //{\r
-       //      if ((byteread[t]=='T') && (byteread[t+1]=='A') && (byteread[t+2]=='G'))\r
-       //      {\r
-       //              System.out.println("ID3v1 detected at offset "+t);\r
-       //              throw newBitstreamException(INVALIDFRAME, null);\r
-       //      }       \r
-       //}\r
-       \r
-       for (int k=0;k<bytesize;k=k+4)\r
-       {\r
-               int convert = 0;\r
-               byte b0 = 0;\r
-               byte b1 = 0;\r
-               byte b2 = 0;\r
-               byte b3 = 0;\r
-               b0 = byteread[k];\r
-               if (k+1<bytesize) b1 = byteread[k+1];\r
-               if (k+2<bytesize) b2 = byteread[k+2];\r
-               if (k+3<bytesize) b3 = byteread[k+3];\r
-               framebuffer[b++] = ((b0 << 24) &0xFF000000) | ((b1 << 16) & 0x00FF0000) | ((b2 << 8) & 0x0000FF00) | (b3 & 0x000000FF);\r
-       }\r
-       wordpointer = 0;\r
-    bitindex = 0;\r
-  }\r
-\r
-  /**\r
-   * Read bits from buffer into the lower bits of an unsigned int.\r
-   * The LSB contains the latest read bit of the stream.\r
-   * (1 <= number_of_bits <= 16)\r
-   */\r
-  public int get_bits(int number_of_bits)\r
-  {\r
-       int                             returnvalue = 0;\r
-       int                     sum = bitindex + number_of_bits;\r
-\r
-       // E.B\r
-       // There is a problem here, wordpointer could be -1 ?!\r
-    if (wordpointer < 0) wordpointer = 0;\r
-    // E.B : End.\r
-\r
-       if (sum <= 32)\r
-       {\r
-          // all bits contained in *wordpointer\r
-          returnvalue = (framebuffer[wordpointer] >>> (32 - sum)) & bitmask[number_of_bits];\r
-          // returnvalue = (wordpointer[0] >> (32 - sum)) & bitmask[number_of_bits];\r
-          if ((bitindex += number_of_bits) == 32)\r
-          {\r
-                bitindex = 0;\r
-                wordpointer++; // added by me!\r
-          }\r
-          return returnvalue;\r
-    }\r
-\r
-    // E.B : Check that ?\r
-    //((short[])&returnvalue)[0] = ((short[])wordpointer + 1)[0];\r
-    //wordpointer++; // Added by me!\r
-    //((short[])&returnvalue + 1)[0] = ((short[])wordpointer)[0];\r
-       int Right = (framebuffer[wordpointer] & 0x0000FFFF);\r
-       wordpointer++;\r
-       int Left = (framebuffer[wordpointer] & 0xFFFF0000);\r
-       returnvalue = ((Right << 16) & 0xFFFF0000) | ((Left >>> 16)& 0x0000FFFF);\r
-\r
-    returnvalue >>>= 48 - sum; // returnvalue >>= 16 - (number_of_bits - (32 - bitindex))\r
-    returnvalue &= bitmask[number_of_bits];\r
-    bitindex = sum - 32;\r
-    return returnvalue;\r
-}\r
-\r
-       /**\r
-        * Set the word we want to sync the header to.\r
-        * In Big-Endian byte order\r
-        */\r
-       void set_syncword(int syncword0)\r
-       {\r
-               syncword = syncword0 & 0xFFFFFF3F;\r
-               single_ch_mode = ((syncword0 & 0x000000C0) == 0x000000C0);\r
-       }\r
-       /**\r
-        * Reads the exact number of bytes from the source\r
-        * input stream into a byte array.\r
-        *\r
-        * @param b             The byte array to read the specified number\r
-        *                              of bytes into.\r
-        * @param offs  The index in the array where the first byte\r
-        *                              read should be stored.\r
-        * @param len   the number of bytes to read.\r
-        *\r
-        * @exception BitstreamException is thrown if the specified\r
-        *              number of bytes could not be read from the stream.\r
-        */\r
-       private int readFully(byte[] b, int offs, int len)\r
-               throws BitstreamException\r
-       {               \r
-               int nRead = 0;\r
-               try\r
-               {\r
-                       while (len > 0)\r
-                       {\r
-                               int bytesread = source.read(b, offs, len);\r
-                               if (bytesread == -1)\r
-                               {\r
-                                       while (len-->0)\r
-                                       {\r
-                                               b[offs++] = 0;\r
-                                       }\r
-                                       break;\r
-                                       //throw newBitstreamException(UNEXPECTED_EOF, new EOFException());\r
-                               }\r
-                               nRead = nRead + bytesread;\r
-                               offs += bytesread;\r
-                               len -= bytesread;\r
-                       }\r
-               }\r
-               catch (IOException ex)\r
-               {\r
-                       throw newBitstreamException(STREAM_ERROR, ex);\r
-               }\r
-               return nRead;\r
-       }\r
-\r
-       /**\r
-        * Simlar to readFully, but doesn't throw exception when\r
-        * EOF is reached.\r
-        */\r
-       private int readBytes(byte[] b, int offs, int len)\r
-               throws BitstreamException\r
-       {\r
-               int totalBytesRead = 0;\r
-               try\r
-               {\r
-                       while (len > 0)\r
-                       {\r
-                               int bytesread = source.read(b, offs, len);\r
-                               if (bytesread == -1)\r
-                               {\r
-                                       break;\r
-                               }\r
-                               totalBytesRead += bytesread;\r
-                               offs += bytesread;\r
-                               len -= bytesread;\r
-                       }\r
-               }\r
-               catch (IOException ex)\r
-               {\r
-                       throw newBitstreamException(STREAM_ERROR, ex);\r
-               }\r
-               return totalBytesRead;\r
-       }\r
-}\r
+/*
+ * 11/19/04  1.0 moved to LGPL.
+ * 
+ * 11/17/04     Uncomplete frames discarded. E.B, javalayer@javazoom.net 
+ *
+ * 12/05/03     ID3v2 tag returned. E.B, javalayer@javazoom.net 
+ *
+ * 12/12/99     Based on Ibitstream. Exceptions thrown on errors,
+ *                      Temporary removed seek functionality. mdm@techie.com
+ *
+ * 02/12/99 : Java Conversion by E.B , javalayer@javazoom.net
+ *
+ * 04/14/97 : Added function prototypes for new syncing and seeking
+ * mechanisms. Also made this file portable. Changes made by Jeff Tsay
+ *
+ *  @(#) ibitstream.h 1.5, last edit: 6/15/94 16:55:34
+ *  @(#) Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de)
+ *  @(#) Berlin University of Technology
+ *-----------------------------------------------------------------------
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as published
+ *   by the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+
+/**
+ * The <code>Bistream</code> class is responsible for parsing an MPEG audio
+ * bitstream.
+ * 
+ * <b>REVIEW:</b> much of the parsing currently occurs in the various decoders.
+ * This should be moved into this class and associated inner classes.
+ */
+@LATTICE("FB<F,FF<F,WP<BI,FF*,WP*,BI*")
+@METHODDEFAULT("OUT<THIS,THIS<VAR,VAR<IN,VAR*,THISLOC=THIS,GLOBALLOC=IN")
+public final class Bitstream implements BitstreamErrors {
+  /**
+   * Synchronization control constant for the initial synchronization to the
+   * start of a frame.
+   */
+  @LOC("F")
+  static byte INITIAL_SYNC = 0;
+
+  /**
+   * Synchronization control constant for non-initial frame synchronizations.
+   */
+
+  @LOC("F")
+  static byte STRICT_SYNC = 1;
+
+  // max. 1730 bytes per frame: 144 * 384kbit/s / 32000 Hz + 2 Bytes CRC
+  /**
+   * Maximum size of the frame buffer.
+   */
+  @LOC("F")
+  private static final int BUFFER_INT_SIZE = 433;
+
+  /**
+   * The frame buffer that holds the data for the current frame.
+   */
+  @LOC("FB")
+  private final int[] framebuffer = new int[BUFFER_INT_SIZE];
+
+  /**
+   * Number of valid bytes in the frame buffer.
+   */
+  @LOC("F")
+  private int framesize;
+
+  /**
+   * The bytes read from the stream.
+   */
+  @LOC("FB")
+  private byte[] frame_bytes = new byte[BUFFER_INT_SIZE * 4];
+
+  /**
+   * Index into <code>framebuffer</code> where the next bits are retrieved.
+   */
+  @LOC("WP")
+  private int wordpointer;
+
+  /**
+   * Number (0-31, from MSB to LSB) of next bit for get_bits()
+   */
+  @LOC("BI")
+  private int bitindex;
+
+  /**
+   * The current specified syncword
+   */
+  @LOC("F")
+  private int syncword;
+
+  /**
+   * Audio header position in stream.
+   */
+  @LOC("F")
+  private int header_pos = 0;
+
+  /**
+        *
+        */
+  @LOC("F")
+  private boolean single_ch_mode;
+  // private int current_frame_number;
+  // private int last_frame_number;
+
+  @LOC("F")
+  private final int bitmask[] = {
+      0, // dummy
+      0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
+      0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, 0x00001FFF, 0x00003FFF,
+      0x00007FFF, 0x0000FFFF, 0x0001FFFF };
+
+  @LOC("F")
+  private final PushbackInputStream source;
+
+  @LOC("F")
+  private final Header header = new Header();
+
+  @LOC("F")
+  private final byte syncbuf[] = new byte[4];
+
+  @LOC("F")
+  private Crc16[] crc = new Crc16[1];
+
+  @LOC("F")
+  private byte[] rawid3v2 = null;
+
+  @LOC("FF")
+  private boolean firstframe = true;
+
+  private BitReserve br;
+  private int main_data_begin;
+  private int frame_start;
+
+  /**
+   * Construct a IBitstream that reads data from a given InputStream.
+   * 
+   * @param in
+   *          The InputStream to read from.
+   */
+  public Bitstream(InputStream in) {
+    if (in == null)
+      throw new NullPointerException("in");
+    in = new BufferedInputStream(in);
+    loadID3v2(in);
+    firstframe = true;
+    // source = new PushbackInputStream(in, 1024);
+    source = new PushbackInputStream(in, BUFFER_INT_SIZE * 4);
+
+    closeFrame();
+    // current_frame_number = -1;
+    // last_frame_number = -1;
+
+    br = new BitReserve();
+
+  }
+
+  /**
+   * Return position of the first audio header.
+   * 
+   * @return size of ID3v2 tag frames.
+   */
+  public int header_pos() {
+    return header_pos;
+  }
+
+  /**
+   * Load ID3v2 frames.
+   * 
+   * @param in
+   *          MP3 InputStream.
+   * @author JavaZOOM
+   */
+  private void loadID3v2(InputStream in) {
+    int size = -1;
+    try {
+      // Read ID3v2 header (10 bytes).
+      in.mark(10);
+      size = readID3v2Header(in);
+      header_pos = size;
+    } catch (IOException e) {
+    } finally {
+      try {
+        // Unread ID3v2 header (10 bytes).
+        in.reset();
+      } catch (IOException e) {
+      }
+    }
+    // Load ID3v2 tags.
+    try {
+      if (size > 0) {
+        rawid3v2 = new byte[size];
+        in.read(rawid3v2, 0, rawid3v2.length);
+      }
+    } catch (IOException e) {
+    }
+  }
+
+  /**
+   * Parse ID3v2 tag header to find out size of ID3v2 frames.
+   * 
+   * @param in
+   *          MP3 InputStream
+   * @return size of ID3v2 frames + header
+   * @throws IOException
+   * @author JavaZOOM
+   */
+  private int readID3v2Header(InputStream in) throws IOException {
+    byte[] id3header = new byte[4];
+    int size = -10;
+    in.read(id3header, 0, 3);
+    // Look for ID3v2
+    if ((id3header[0] == 'I') && (id3header[1] == 'D') && (id3header[2] == '3')) {
+      in.read(id3header, 0, 3);
+      int majorVersion = id3header[0];
+      int revision = id3header[1];
+      in.read(id3header, 0, 4);
+      size =
+          (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]);
+    }
+    return (size + 10);
+  }
+
+  /**
+   * Return raw ID3v2 frames + header.
+   * 
+   * @return ID3v2 InputStream or null if ID3v2 frames are not available.
+   */
+  public InputStream getRawID3v2() {
+    if (rawid3v2 == null)
+      return null;
+    else {
+      ByteArrayInputStream bain = new ByteArrayInputStream(rawid3v2);
+      return bain;
+    }
+  }
+
+  /**
+   * Close the Bitstream.
+   * 
+   * @throws BitstreamException
+   */
+  public void close() throws BitstreamException {
+    try {
+      source.close();
+    } catch (IOException ex) {
+      throw newBitstreamException(STREAM_ERROR, ex);
+    }
+  }
+
+  /**
+   * Reads and parses the next frame from the input source.
+   * 
+   * @return the Header describing details of the frame read, or null if the end
+   *         of the stream has been reached.
+   */
+  public Header readFrame() throws BitstreamException {
+    Header result = null;
+    try {
+      result = readNextFrame();
+      // E.B, Parse VBR (if any) first frame.
+      if (firstframe == true) {
+        result.parseVBR(frame_bytes);
+        firstframe = false;
+      }
+    } catch (BitstreamException ex) {
+      if ((ex.getErrorCode() == INVALIDFRAME)) {
+        // Try to skip this frame.
+        // System.out.println("INVALIDFRAME");
+        try {
+          closeFrame();
+          result = readNextFrame();
+        } catch (BitstreamException e) {
+          if ((e.getErrorCode() != STREAM_EOF)) {
+            // wrap original exception so stack trace is maintained.
+            throw newBitstreamException(e.getErrorCode(), e);
+          }
+        }
+      } else if ((ex.getErrorCode() != STREAM_EOF)) {
+        // wrap original exception so stack trace is maintained.
+        throw newBitstreamException(ex.getErrorCode(), ex);
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Read next MP3 frame.
+   * 
+   * @return MP3 frame header.
+   * @throws BitstreamException
+   */
+  private Header readNextFrame() throws BitstreamException {
+    if (framesize == -1) {
+      nextFrame();
+    }
+    return header;
+  }
+
+  /**
+   * Read next MP3 frame.
+   * 
+   * @throws BitstreamException
+   */
+  private void nextFrame() throws BitstreamException {
+    // entire frame is read by the header class.
+    header.read_header(this, crc);
+  }
+
+  /**
+   * Unreads the bytes read from the frame.
+   * 
+   * @throws BitstreamException
+   */
+  // REVIEW: add new error codes for this.
+  public void unreadFrame() throws BitstreamException {
+    if (wordpointer == -1 && bitindex == -1 && (framesize > 0)) {
+      try {
+        source.unread(frame_bytes, 0, framesize);
+      } catch (IOException ex) {
+        throw newBitstreamException(STREAM_ERROR);
+      }
+    }
+  }
+
+  /**
+   * Close MP3 frame.
+   */
+  public void closeFrame() {
+    framesize = -1;
+    wordpointer = -1;
+    bitindex = -1;
+  }
+
+  /**
+   * Determines if the next 4 bytes of the stream represent a frame header.
+   */
+  public boolean isSyncCurrentPosition(int syncmode) throws BitstreamException {
+    int read = readBytes(syncbuf, 0, 4);
+    int headerstring =
+        ((syncbuf[0] << 24) & 0xFF000000) | ((syncbuf[1] << 16) & 0x00FF0000)
+            | ((syncbuf[2] << 8) & 0x0000FF00) | ((syncbuf[3] << 0) & 0x000000FF);
+
+    try {
+      source.unread(syncbuf, 0, read);
+    } catch (IOException ex) {
+    }
+
+    boolean sync = false;
+    switch (read) {
+    case 0:
+      sync = true;
+      break;
+    case 4:
+      sync = isSyncMark(headerstring, syncmode, syncword);
+      break;
+    }
+
+    return sync;
+  }
+
+  // REVIEW: this class should provide inner classes to
+  // parse the frame contents. Eventually, readBits will
+  // be removed.
+  public int readBits(int n) {
+    return get_bits(n);
+  }
+
+  public int peek_bits(int number_of_bits) {
+
+    int peekbitindex = bitindex;
+    int peekPointer = wordpointer;
+
+    int returnvalue = 0;
+    int sum = peekbitindex + number_of_bits;
+
+    if (peekPointer < 0) {
+      peekPointer = 0;
+    }
+
+    if (sum <= 32) {
+      // all bits contained in *wordpointer
+      returnvalue = (framebuffer[peekPointer] >>> (32 - sum)) & bitmask[number_of_bits];
+      // returnvalue = (wordpointer[0] >> (32 - sum)) &
+      // bitmask[number_of_bits];
+      if ((peekbitindex += number_of_bits) == 32) {
+        peekbitindex = 0;
+        peekPointer++; // added by me!
+      }
+      return returnvalue;
+    }
+
+    // E.B : Check that ?
+    // ((short[])&returnvalue)[0] = ((short[])wordpointer + 1)[0];
+    // wordpointer++; // Added by me!
+    // ((short[])&returnvalue + 1)[0] = ((short[])wordpointer)[0];
+    int Right = (framebuffer[peekPointer] & 0x0000FFFF);
+    peekPointer++;
+    int Left = (framebuffer[peekPointer] & 0xFFFF0000);
+    returnvalue = ((Right << 16) & 0xFFFF0000) | ((Left >>> 16) & 0x0000FFFF);
+
+    returnvalue >>>= 48 - sum; // returnvalue >>= 16 - (number_of_bits - (32
+                               // - bitindex))
+    returnvalue &= bitmask[number_of_bits];
+    peekbitindex = sum - 32;
+    return returnvalue;
+
+  }
+
+  public int readCheckedBits(int n) {
+    // REVIEW: implement CRC check.
+    return get_bits(n);
+  }
+
+  protected BitstreamException newBitstreamException(int errorcode) {
+    return new BitstreamException(errorcode, null);
+  }
+
+  protected BitstreamException newBitstreamException(int errorcode, Throwable throwable) {
+    return new BitstreamException(errorcode, throwable);
+  }
+
+  /**
+   * Get next 32 bits from bitstream. They are stored in the headerstring.
+   * syncmod allows Synchro flag ID The returned value is False at the end of
+   * stream.
+   */
+
+  int syncHeader(byte syncmode) throws BitstreamException {
+    boolean sync;
+    int headerstring;
+    // read additional 2 bytes
+    int bytesRead = readBytes(syncbuf, 0, 3);
+
+    if (bytesRead != 3)
+      throw newBitstreamException(STREAM_EOF, null);
+
+    headerstring =
+        ((syncbuf[0] << 16) & 0x00FF0000) | ((syncbuf[1] << 8) & 0x0000FF00)
+            | ((syncbuf[2] << 0) & 0x000000FF);
+
+    do {
+      headerstring <<= 8;
+
+      if (readBytes(syncbuf, 3, 1) != 1)
+        throw newBitstreamException(STREAM_EOF, null);
+
+      headerstring |= (syncbuf[3] & 0x000000FF);
+
+      sync = isSyncMark(headerstring, syncmode, syncword);
+    } while (!sync);
+
+    // current_frame_number++;
+    // if (last_frame_number < current_frame_number) last_frame_number =
+    // current_frame_number;
+
+    return headerstring;
+  }
+
+  public boolean isSyncMark(int headerstring, int syncmode, int word) {
+    boolean sync = false;
+
+    if (syncmode == INITIAL_SYNC) {
+      // sync = ((headerstring & 0xFFF00000) == 0xFFF00000);
+      sync = ((headerstring & 0xFFE00000) == 0xFFE00000); // SZD: MPEG 2.5
+    } else {
+      sync =
+          ((headerstring & 0xFFF80C00) == word)
+              && (((headerstring & 0x000000C0) == 0x000000C0) == single_ch_mode);
+    }
+
+    // filter out invalid sample rate
+    if (sync)
+      sync = (((headerstring >>> 10) & 3) != 3);
+    // filter out invalid layer
+    if (sync)
+      sync = (((headerstring >>> 17) & 3) != 0);
+    // filter out invalid version
+    if (sync)
+      sync = (((headerstring >>> 19) & 3) != 1);
+
+    return sync;
+  }
+
+  /**
+   * Reads the data for the next frame. The frame is not parsed until parse
+   * frame is called.
+   */
+  int read_frame_data(int bytesize) throws BitstreamException {
+    int numread = 0;
+    numread = readFully(frame_bytes, 0, bytesize);
+    framesize = bytesize;
+    wordpointer = -1;
+    bitindex = -1;
+    return numread;
+  }
+
+  /**
+   * Parses the data previously read with read_frame_data().
+   */
+  @LATTICE("GLOBAL<B,B<BNUM,BNUM<K,K<BYTE,BYTE<THIS,B*,K*,THISLOC=THIS,GLOBALLOC=GLOBAL")
+  void parse_frame() throws BitstreamException {
+    // Convert Bytes read to int
+    @LOC("B") int b = 0;
+    @LOC("BYTE") byte[] byteread = frame_bytes;
+    @LOC("BYTE") int bytesize = framesize;
+
+    // Check ID3v1 TAG (True only if last frame).
+    // for (int t=0;t<(byteread.length)-2;t++)
+    // {
+    // if ((byteread[t]=='T') && (byteread[t+1]=='A') && (byteread[t+2]=='G'))
+    // {
+    // System.out.println("ID3v1 detected at offset "+t);
+    // throw newBitstreamException(INVALIDFRAME, null);
+    // }
+    // }
+
+    for (@LOC("K") int k = 0; k < bytesize; k = k + 4) {
+      @LOC("BYTE") int convert = 0;
+      @LOC("BNUM") byte b0 = 0;
+      @LOC("BNUM") byte b1 = 0;
+      @LOC("BNUM") byte b2 = 0;
+      @LOC("BNUM") byte b3 = 0;
+      b0 = byteread[k];
+      if (k + 1 < bytesize)
+        b1 = byteread[k + 1];
+      if (k + 2 < bytesize)
+        b2 = byteread[k + 2];
+      if (k + 3 < bytesize)
+        b3 = byteread[k + 3];
+      framebuffer[b++] =
+          ((b0 << 24) & 0xFF000000) | ((b1 << 16) & 0x00FF0000) | ((b2 << 8) & 0x0000FF00)
+              | (b3 & 0x000000FF);
+    }
+    wordpointer = 0;
+    bitindex = 0;
+  }
+
+  /**
+   * Read bits from buffer into the lower bits of an unsigned int. The LSB
+   * contains the latest read bit of the stream. (1 <= number_of_bits <= 16)
+   */
+  @LATTICE("OUT<RL,RL<THIS,THIS<IN,OUT*,THISLOC=THIS,RETURNLOC=OUT")
+  public int get_bits(@LOC("IN") int number_of_bits) {
+
+    @LOC("OUT") int returnvalue = 0;
+    @LOC("THIS,Bitstream.BI") int sum = bitindex + number_of_bits;
+
+    // E.B
+    // There is a problem here, wordpointer could be -1 ?!
+    if (wordpointer < 0)
+      wordpointer = 0;
+    // E.B : End.
+
+    if (sum <= 32) {
+      // all bits contained in *wordpointer
+      returnvalue = (framebuffer[wordpointer] >>> (32 - sum)) & bitmask[number_of_bits];
+      // returnvalue = (wordpointer[0] >> (32 - sum)) & bitmask[number_of_bits];
+      if ((bitindex += number_of_bits) == 32) {
+        bitindex = 0;
+        wordpointer++; // added by me!
+      }
+      return returnvalue;
+    }
+
+    // E.B : Check that ?
+    // ((short[])&returnvalue)[0] = ((short[])wordpointer + 1)[0];
+    // wordpointer++; // Added by me!
+    // ((short[])&returnvalue + 1)[0] = ((short[])wordpointer)[0];
+    @LOC("RL") int Right = (framebuffer[wordpointer] & 0x0000FFFF);
+    wordpointer++;
+    @LOC("RL") int Left = (framebuffer[wordpointer] & 0xFFFF0000);
+    returnvalue = ((Right << 16) & 0xFFFF0000) | ((Left >>> 16) & 0x0000FFFF);
+
+    returnvalue >>>= 48 - sum; // returnvalue >>= 16 - (number_of_bits - (32 -
+                               // bitindex))
+    returnvalue &= bitmask[number_of_bits];
+    bitindex = sum - 32;
+    return returnvalue;
+  }
+
+  /**
+   * Set the word we want to sync the header to. In Big-Endian byte order
+   */
+  void set_syncword(@LOC("IN") int syncword0) {
+    syncword = syncword0 & 0xFFFFFF3F;
+    single_ch_mode = ((syncword0 & 0x000000C0) == 0x000000C0);
+  }
+
+  /**
+   * Reads the exact number of bytes from the source input stream into a byte
+   * array.
+   * 
+   * @param b
+   *          The byte array to read the specified number of bytes into.
+   * @param offs
+   *          The index in the array where the first byte read should be stored.
+   * @param len
+   *          the number of bytes to read.
+   * 
+   * @exception BitstreamException
+   *              is thrown if the specified number of bytes could not be read
+   *              from the stream.
+   */
+  @LATTICE("OUT<VAR,VAR<THIS,THIS<IN,IN*,VAR*,THISLOC=THIS")
+  @RETURNLOC("OUT")
+  private int readFully(@LOC("OUT") byte[] b, @LOC("IN") int offs, @LOC("IN") int len)
+      throws BitstreamException {
+    @LOC("VAR") int nRead = 0;
+    try {
+      while (len > 0) {
+        @LOC("IN") int bytesread = source.read(b, offs, len);
+        if (bytesread == -1) {
+          while (len-- > 0) {
+            b[offs++] = 0;
+          }
+          break;
+          // throw newBitstreamException(UNEXPECTED_EOF, new EOFException());
+        }
+        nRead = nRead + bytesread;
+        offs += bytesread;
+        len -= bytesread;
+      }
+    } catch (IOException ex) {
+      throw newBitstreamException(STREAM_ERROR, ex);
+    }
+    return nRead;
+  }
+
+  /**
+   * Simlar to readFully, but doesn't throw exception when EOF is reached.
+   */
+  @LATTICE("OUT<VAR,VAR<THIS,THIS<IN,IN*,VAR*,THISLOC=THIS")
+  @RETURNLOC("OUT")
+  private int readBytes(@LOC("OUT") byte[] b, @LOC("IN") int offs, @LOC("IN") int len)
+      throws BitstreamException {
+    @LOC("VAR") int totalBytesRead = 0;
+    try {
+      while (len > 0) {
+        @LOC("IN") int bytesread = source.read(b, offs, len);
+        if (bytesread == -1) {
+          break;
+        }
+        totalBytesRead += bytesread;
+        offs += bytesread;
+        len -= bytesread;
+      }
+    } catch (IOException ex) {
+      throw newBitstreamException(STREAM_ERROR, ex);
+    }
+    return totalBytesRead;
+  }
+
+  public SideInfoBuffer getSideInfoBuffer(int channelType) {
+
+    if (wordpointer < 0)
+      wordpointer = 0;
+
+    SideInfoBuffer sib = new SideInfoBuffer();
+
+    // first, store main_data_begin from the side inforamtion
+    main_data_begin = peek_bits(9);
+    System.out.println("main_data_begin=" + main_data_begin);
+
+    int max;
+    if (channelType == 1) { // mono
+      max = wordpointer + 4;
+    } else {
+      max = wordpointer + 8;
+    }
+
+    try {
+      for (; wordpointer < max; wordpointer++) {
+        sib.setBuffer(wordpointer, framebuffer[wordpointer]);
+      }
+    } catch (ArrayIndexOutOfBoundsException e) {
+      System.out.print("wordpointer=" + wordpointer);
+      System.out.println("framebuffer length=" + framebuffer.length);
+    }
+
+    return sib;
+  }
+
+  public BitReserve getBitReserve(int nSlots) {
+
+    int flush_main;
+    int bytes_to_discard;
+    int i;
+
+    for (i = 0; i < nSlots; i++)
+      br.hputbuf(get_bits(8));
+
+    int main_data_end = br.hsstell() >>> 3; // of previous frame
+
+    if ((flush_main = (br.hsstell() & 7)) != 0) {
+      br.hgetbits(8 - flush_main);
+      main_data_end++;
+    }
+
+    bytes_to_discard = frame_start - main_data_end - main_data_begin;
+
+    frame_start += nSlots;
+
+    if (bytes_to_discard < 0) {
+      System.out.println("HERE?");
+      return null;
+    }
+
+    if (main_data_end > 4096) {
+      frame_start -= 4096;
+      br.rewindNbytes(4096);
+    }
+
+    for (; bytes_to_discard > 0; bytes_to_discard--)
+      br.hgetbits(8);
+
+    return br;
+  }
+}