/** * MediaFrame is an Open Source streaming media platform in Java * which provides a fast, easy to implement and extremely small applet * that enables to view your audio/video content without having * to rely on external player applications or bulky plug-ins. * * Copyright (C) 2004/5 MediaFrame (http://www.mediaframe.org). * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ /** * MediaFrame is an Open Source streaming media platform in Java * which provides a fast, easy to implement and extremely small applet * that enables to view your audio/video content without having * to rely on external player applications or bulky plug-ins. * * Copyright (C) 2004 MediaFrame (http://www.mediaframe.org). * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ package mediaframe.mpeg4.audio.AAC; import java.io.IOException; import java.io.EOFException; import java.io.InputStream; /** * The <code>BitStream</code> class implements 'bit' reading functions from the * MPEG4 audio input stream. */ public final class BitStream { /** The AAC input stream. */ private InputStream is; /** The local buffer of 64 bits. */ private long buffer = 0; /** The pointer into the local buffer. */ private byte pointer = 0; /** The number of readed bytes from the stream. */ private int readedBytes = 0; /** The size of the audio header. */ private int audioHeaderSize; /** * Constructs an <code>BitStream</code> object using the specified MPEG4 * audio input stream. * * @param is * the MPEG4 audio input stream. */ public BitStream(InputStream is) { this(is, 0); } /** * Constructs an <code>BitStream</code> object using the specified MPEG4 * audio input stream and the size of the audio header. * * @param is * the MPEG4 audio input stream. * @param audioHeaderSize * the size of the audio header. */ public BitStream(InputStream is, int audioHeaderSize) { super(); this.is = is; this.audioHeaderSize = audioHeaderSize; } /** * Reads next bit from the input stream and return it as a boolean value. * * @return <tt>true</tt> if the bit equals '1', <tt>false</tt> otherwise. * @throws IOException * raises if an error occurs. */ public boolean next_bit() throws IOException { return next_bits(1) == 1; } /** * Reads next 'n' (up to 64) bits from the input stream. * * @param n * the number of bits to read. * @return the 'n' bits from the input stream. * @throws IOException * raises if an error occurs. */ public long next_bits(int n) throws IOException { if (n > 64) { throw new IOException("Wrong number of bits to read"); } while ((pointer - n) < 0) { read_byte(); } long mask = -1L >>> (64 - n); long result = (buffer >> (pointer - n)) & mask; if (n == 0) { result = 0; } // System.out.println("next_bits: " + n + " " + result); /* * System.out.println("n: " + n); System.out.println("pointer: " + * pointer); System.out.println("Mask: " + mask); * System.out.println("Result: " + result); * System.out.println("Buffer: " + result); */ pointer -= n; return result; } /** * Returns 'n' bits (up to 64) into the input stream. * * @param n * the number of bits to return. */ public void unget_bits(int n) throws IOException { if ((pointer + n) > 64) { throw new IOException("Wrong number of bits to unget"); } pointer += n; } /** * Returns next 'n' (up to 64) bits from the input stream starting on byte * boundary. Does't change the pointer into local buffer. * * @param n * the number of bits to read. * @return the 'n' bits from the input stream. * @throws IOException * raises if an error occurs. */ public long nextbits_byteAligned(int n) throws IOException { int alignSkip = pointer % 8; if (alignSkip == 0) { alignSkip = 8; } skip_bits(alignSkip); long result = next_bits(n); unget_bits(alignSkip + n); return result; } /** * Reads one byte from the input stream into the local buffer. * * @throws IOException * raises if an error occurs. * @throws EOFException * raises if the end of the file has been reached. */ private void read_byte() throws IOException { long c = is.read(); // System.out.println("read_byte: " + Long.toHexString(c)); if (c == -1) throw new EOFException(); buffer = (buffer << 8) + (c & 0xff); pointer += 8; readedBytes++; } /** * Skips 'n' bits from the input stream. * * @param n * the number of bits to skip. * @throws IOException * raises if an error occurs. */ public void skip_bits(int n) throws IOException { while ((pointer - n) < 0) { read_byte(); } pointer -= n; } /** * Skips one bit from the input stream. * * @throws IOException * raises if an error occurs. */ public void skip_bit() throws IOException { while (pointer <= 0) { read_byte(); } pointer--; } /** * Skips one 'marker' (equal to one) bit from the input stream. * * @throws IOException * raises if an error occurs. */ public void marker_bit() throws IOException { while (pointer <= 0) { read_byte(); } /* * if(((buffer >> (pointer - 1)) & 1) != 1) { throw new * IOException("Stream error: the market bit should be equal to '1'"); } */ pointer--; } /** * Returns <tt>true</tt> if the current position of the bitstream is on byte * boundary. */ public boolean isByteAligned() { return (pointer % 8) == 0; } /** * Aligns the current position of the bitstream on byte boundary. * * @throws IOException * raises if an error occurs. */ public void byteAlign() throws IOException { skip_bits(pointer % 8); } /** * Aligns the current position of the bitstream on audio header size * boundary. * * @throws IOException * raises if an error occurs. */ public void alignHeader() throws IOException { skip_bits(pointer % 8); if (audioHeaderSize > readedBytes) { skip_bits((audioHeaderSize - readedBytes) * 8); } } /** * Finds the next start code (23 zeros followed by a single bit with the * value one) in the bitstream. * * @throws IOException * raises if an error occurs. */ public void next_start_code() throws IOException { boolean found = false; int skipped = pointer % 8; byteAlign(); while (!found) { while (!(next_bits(8) == 0)) { skipped += 8; } skipped += 8; if (next_bits(16) == 1) { skipped += 16; found = true; } else { unget_bits(16); } } // System.out.println("next_start_code() skipped " + (skipped - 24) + // " bits"); } public void print_next_bits(int n) throws IOException { String stream = Long.toBinaryString(next_bits(n)); for (int i = stream.length(); i < n; i++) { stream = '0' + stream; } System.out.println("bitstream = " + stream); unget_bits(n); } }