/***************************************************************************
* JLayerME is a JAVA library that decodes/plays/converts MPEG 1/2 Layer 3.
* Project Homepage: http://www.javazoom.net/javalayer/javalayerme.html.
* Copyright (C) JavaZOOM 1999-2005.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*---------------------------------------------------------------------------
*/
package javazoom.jlme.decoder;
import java.io.IOException;
import java.io.InputStream;
/**
* 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.
*
* @author micah
* @created December 8, 2001
*/
public final class BitStream {
static final byte INITIAL_SYNC = 0;
static final byte STRICT_SYNC = 1;
private final static int BUFFER_INT_SIZE = 433;
private final static int bitmask[] = { 0, 0x00000001, 0x00000003,
0x00000007, 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, 0x0001FFFF };
private static PushBackStream source;
private static final int[] framebuffer = new int[BUFFER_INT_SIZE];
private static int framesize;
private static final byte[] frame_bytes = new byte[BUFFER_INT_SIZE * 4];
private static int wordpointer;
private static int bitindex;
private static int syncword;
private static boolean single_ch_mode;
private final static Header header = new Header();
private final static byte syncbuf[] = new byte[4];
public BitStream(InputStream in) {
source = new PushBackStream(in, 512);
closeFrame();
Header.syncmode = INITIAL_SYNC;
}
static int read;
public final boolean isSyncCurrentPosition(int syncmode) throws IOException {
if ((read = source.read(syncbuf, 0, 4)) > 0) { // if(read>=0){
source.unread(syncbuf, 0, read);
if (read == 4) {
headerstring = ((syncbuf[0] << 24) & 0xFF000000)
| ((syncbuf[1] << 16) & 0x00FF0000)
| ((syncbuf[2] << 8) & 0x0000FF00)
| ((syncbuf[3] << 0) & 0x000000FF);
return isSyncMark(headerstring, syncmode, syncword);
}
}
return true;
}
/**
* Gets the syncMark attribute of the Bitstream object
*
* @param headerstring
* Description of Parameter
* @param syncmode
* Description of Parameter
* @param word
* Description of Parameter
* @return The syncMark value
*/
static boolean sync;
public final boolean isSyncMark(int headerstring, int syncmode, int word) {
if (syncmode == INITIAL_SYNC) {
sync = ((headerstring & 0xFFF00000) == 0xFFF00000);
} else {
sync = ((headerstring & 0xFFF80C00) == word)
&& (((headerstring & 0x000000C0) == 0x000000C0) == single_ch_mode);
}
// filter out invalid sample rate
if (sync)
if (sync = (((headerstring >>> 10) & 3) != 3))
if (sync = (((headerstring >>> 17) & 3) != 0))
sync = (((headerstring >>> 19) & 3) != 1);
return sync;
}
static int sum, returnvalue;
public final int readbits(int num) {
sum = bitindex + num;
if (sum <= 32) {
returnvalue = (framebuffer[wordpointer] >>> (32 - sum))
& bitmask[num];
if ((bitindex += num) == 32) {
bitindex = 0;
wordpointer++;
}
return returnvalue;
}
returnvalue = (((framebuffer[wordpointer++] & 0x0000FFFF) << 16) & 0xFFFF0000)
| (((framebuffer[wordpointer] & 0xFFFF0000) >>> 16) & 0x0000FFFF);
returnvalue >>>= 48 - sum;
returnvalue &= bitmask[num];
bitindex = sum - 32;
return returnvalue;
}
/**
* Description of the Method
*
* @exception IOException
* Description of Exception
*/
public void close() throws IOException {
source.close();
}
/**
* 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.
* @exception IOException
* Description of Exception
*/
public Header readFrame() throws IOException {
// if (framesize == -1) {
header.read_header(this);
// }
return header;
}
/**
* Unreads the bytes read from the frame.
*
* @exception IOException
* Description of Exception
* @throws BitstreamException
*/
// REVIEW: add new error codes for this.
public final void unreadFrame() throws IOException {
if (wordpointer == -1 && bitindex == -1 && (framesize > 0)) {
source.unread(frame_bytes, 0, framesize);
}
}
/** Description of the Method */
public void closeFrame() {
framesize = wordpointer = bitindex = -1;
}
/**
* Set the word we want to sync the header to. In Big-Endian byte order
*
* @param syncword0
* Description of Parameter
*/
final void set_syncword(int syncword0) {
syncword = syncword0 & 0xFFFFFF3F;
single_ch_mode = ((syncword0 & 0x000000C0) == 0x000000C0);
}
static int bytesread, headerstring;
int syncHeader(byte syncmode) throws IOException {
if ((bytesread = source.read(syncbuf, 0, 3)) != 3)
return -1;
headerstring = syncbuf[0] << 16 & 0xff0000 | syncbuf[1] << 8 & 0xff00
| syncbuf[2] << 0 & 0xff;
do {
headerstring <<= 8;
if (source.read(syncbuf, 3, 1) != 1)
return -1;
headerstring |= syncbuf[3] & 0xff;
} while (!isSyncMark(headerstring, syncmode, syncword));
return headerstring;
}
/**
* Reads the data for the next frame. The frame is not parsed until parse
* frame is called.
*
* @param bytesize
* Description of Parameter
* @exception IOException
* Description of Exception
*/
final void read_frame_data(int bytesize) throws IOException {
if (bytesize >= 0) {
framesize = bytesize;
wordpointer = bitindex = -1;
source.read(frame_bytes, 0, bytesize);
}
}
static int b, k;
static byte b0, b1, b2, b3;
/** Parses the data previously read with read_frame_data(). */
final void parse_frame() {
// Convert Bytes read to int
for (k = 0, b = 0; k < framesize; k += 4) {
b0 = frame_bytes[k];
if (k + 3 < framesize) {
b3 = frame_bytes[k + 3];
b2 = frame_bytes[k + 2];
b1 = frame_bytes[k + 1];
} else if (k + 2 < framesize) {
b3 = 0;
b2 = frame_bytes[k + 2];
b1 = frame_bytes[k + 1];
} else if (k + 1 < framesize) {
b2 = b3 = 0;
b1 = frame_bytes[k + 1];
}
framebuffer[b++] = ((b0 << 24) & 0xFF000000)
| ((b1 << 16) & 0x00FF0000) | ((b2 << 8) & 0x0000FF00)
| (b3 & 0x000000FF);
}
wordpointer = bitindex = 0;
}
}