updated annotation
authordavid <david>
Wed, 13 Jul 2011 18:54:28 +0000 (18:54 +0000)
committerdavid <david>
Wed, 13 Jul 2011 18:54:28 +0000 (18:54 +0000)
Robust/src/Tests/ssJava/mp3decoder/Bitstream.java

index 2692393..a975045 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 final byte               INITIAL_SYNC = 0;\r
-\r
-       /**\r
-        * Synchronization control constant for non-initial frame\r
-        * synchronizations.\r
-        */\r
-       static final 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;
+
+
+       /**
+        * 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;
+       }
+
+       /**
+        * 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 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;
+       }
+}