Path: blob/main/src/lwjgl/java/javazoom/jl/decoder/Bitstream.java
8650 views
/*1* 11/19/04 1.0 moved to LGPL.2*3* 11/17/04 Uncomplete frames discarded. E.B, [email protected]4*5* 12/05/03 ID3v2 tag returned. E.B, [email protected]6*7* 12/12/99 Based on Ibitstream. Exceptions thrown on errors,8* Temporary removed seek functionality. [email protected]9*10* 02/12/99 : Java Conversion by E.B , [email protected]11*12* 04/14/97 : Added function prototypes for new syncing and seeking13* mechanisms. Also made this file portable. Changes made by Jeff Tsay14*15* @(#) ibitstream.h 1.5, last edit: 6/15/94 16:55:3416* @(#) Copyright (C) 1993, 1994 Tobias Bading ([email protected])17* @(#) Berlin University of Technology18*-----------------------------------------------------------------------19* This program is free software; you can redistribute it and/or modify20* it under the terms of the GNU Library General Public License as published21* by the Free Software Foundation; either version 2 of the License, or22* (at your option) any later version.23*24* This program is distributed in the hope that it will be useful,25* but WITHOUT ANY WARRANTY; without even the implied warranty of26* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the27* GNU Library General Public License for more details.28*29* You should have received a copy of the GNU Library General Public30* License along with this program; if not, write to the Free Software31* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.32*----------------------------------------------------------------------33*/3435package javazoom.jl.decoder;3637import java.io.BufferedInputStream;38import java.io.ByteArrayInputStream;39import java.io.IOException;40import java.io.InputStream;41import java.io.PushbackInputStream;424344/**45* The <code>Bistream</code> class is responsible for parsing46* an MPEG audio bitstream.47*48* <b>REVIEW:</b> much of the parsing currently occurs in the49* various decoders. This should be moved into this class and associated50* inner classes.51*/52public final class Bitstream implements BitstreamErrors53{54/**55* Synchronization control constant for the initial56* synchronization to the start of a frame.57*/58static byte INITIAL_SYNC = 0;5960/**61* Synchronization control constant for non-initial frame62* synchronizations.63*/64static byte STRICT_SYNC = 1;6566// max. 1730 bytes per frame: 144 * 384kbit/s / 32000 Hz + 2 Bytes CRC67/**68* Maximum size of the frame buffer.69*/70private static final int BUFFER_INT_SIZE = 433;7172/**73* The frame buffer that holds the data for the current frame.74*/75private final int[] framebuffer = new int[BUFFER_INT_SIZE];7677/**78* Number of valid bytes in the frame buffer.79*/80private int framesize;8182/**83* The bytes read from the stream.84*/85private byte[] frame_bytes = new byte[BUFFER_INT_SIZE*4];8687/**88* Index into <code>framebuffer</code> where the next bits are89* retrieved.90*/91private int wordpointer;9293/**94* Number (0-31, from MSB to LSB) of next bit for get_bits()95*/96private int bitindex;9798/**99* The current specified syncword100*/101private int syncword;102103/**104* Audio header position in stream.105*/106private int header_pos = 0;107108/**109*110*/111private boolean single_ch_mode;112//private int current_frame_number;113//private int last_frame_number;114115private final int bitmask[] = {0, // dummy1160x00000001, 0x00000003, 0x00000007, 0x0000000F,1170x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,1180x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,1190x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,1200x0001FFFF };121122private final PushbackInputStream source;123124private final Header header = new Header();125126private final byte syncbuf[] = new byte[4];127128private Crc16[] crc = new Crc16[1];129130private byte[] rawid3v2 = null;131132private boolean firstframe = true;133134135/**136* Construct a IBitstream that reads data from a137* given InputStream.138*139* @param in The InputStream to read from.140*/141public Bitstream(InputStream in)142{143if (in==null) throw new NullPointerException("in");144in = new BufferedInputStream(in);145loadID3v2(in);146firstframe = true;147//source = new PushbackInputStream(in, 1024);148source = new PushbackInputStream(in, BUFFER_INT_SIZE*4);149150closeFrame();151//current_frame_number = -1;152//last_frame_number = -1;153}154155/**156* Return position of the first audio header.157* @return size of ID3v2 tag frames.158*/159public int header_pos()160{161return header_pos;162}163164/**165* Load ID3v2 frames.166* @param in MP3 InputStream.167* @author JavaZOOM168*/169private void loadID3v2(InputStream in)170{171int size = -1;172try173{174// Read ID3v2 header (10 bytes).175in.mark(10);176size = readID3v2Header(in);177header_pos = size;178}179catch (IOException e)180{}181finally182{183try184{185// Unread ID3v2 header (10 bytes).186in.reset();187}188catch (IOException e)189{}190}191// Load ID3v2 tags.192try193{194if (size > 0)195{196rawid3v2 = new byte[size];197in.read(rawid3v2,0,rawid3v2.length);198}199}200catch (IOException e)201{}202}203204/**205* Parse ID3v2 tag header to find out size of ID3v2 frames.206* @param in MP3 InputStream207* @return size of ID3v2 frames + header208* @throws IOException209* @author JavaZOOM210*/211private int readID3v2Header(InputStream in) throws IOException212{213byte[] id3header = new byte[4];214int size = -10;215in.read(id3header,0,3);216// Look for ID3v2217if ( (id3header[0]=='I') && (id3header[1]=='D') && (id3header[2]=='3'))218{219in.read(id3header,0,3);220int majorVersion = id3header[0];221int revision = id3header[1];222in.read(id3header,0,4);223size = (int) (id3header[0] << 21) + (id3header[1] << 14) + (id3header[2] << 7) + (id3header[3]);224}225return (size+10);226}227228/**229* Return raw ID3v2 frames + header.230* @return ID3v2 InputStream or null if ID3v2 frames are not available.231*/232public InputStream getRawID3v2()233{234if (rawid3v2 == null) return null;235else236{237ByteArrayInputStream bain = new ByteArrayInputStream(rawid3v2);238return bain;239}240}241242/**243* Close the Bitstream.244* @throws BitstreamException245*/246public void close() throws BitstreamException247{248try249{250source.close();251}252catch (IOException ex)253{254throw newBitstreamException(STREAM_ERROR, ex);255}256}257258/**259* Reads and parses the next frame from the input source.260*261* @return the Header describing details of the frame read,262* or null if the end of the stream has been reached.263*/264public Header readFrame() throws BitstreamException265{266Header result = null;267try268{269result = readNextFrame();270// E.B, Parse VBR (if any) first frame.271if (firstframe == true)272{273result.parseVBR(frame_bytes);274firstframe = false;275}276}277catch (BitstreamException ex)278{279if ((ex.getErrorCode()==INVALIDFRAME))280{281// Try to skip this frame.282//System.out.println("INVALIDFRAME");283try284{285closeFrame();286result = readNextFrame();287}288catch (BitstreamException e)289{290if ((e.getErrorCode()!=STREAM_EOF))291{292// wrap original exception so stack trace is maintained.293throw newBitstreamException(e.getErrorCode(), e);294}295}296}297else if ((ex.getErrorCode()!=STREAM_EOF))298{299// wrap original exception so stack trace is maintained.300throw newBitstreamException(ex.getErrorCode(), ex);301}302}303return result;304}305306/**307* Read next MP3 frame.308*309* @return MP3 frame header.310* @throws BitstreamException311*/312private Header readNextFrame() throws BitstreamException313{314if (framesize == -1)315{316nextFrame();317}318return header;319}320321322/**323* Read next MP3 frame.324*325* @throws BitstreamException326*/327private void nextFrame() throws BitstreamException328{329// entire frame is read by the header class.330header.read_header(this, crc);331}332333/**334* Unreads the bytes read from the frame.335*336* @throws BitstreamException337*/338// REVIEW: add new error codes for this.339public void unreadFrame() throws BitstreamException340{341if (wordpointer==-1 && bitindex==-1 && (framesize>0))342{343try344{345source.unread(frame_bytes, 0, framesize);346}347catch (IOException ex)348{349throw newBitstreamException(STREAM_ERROR);350}351}352}353354/**355* Close MP3 frame.356*/357public void closeFrame()358{359framesize = -1;360wordpointer = -1;361bitindex = -1;362}363364/**365* Determines if the next 4 bytes of the stream represent a366* frame header.367*/368public boolean isSyncCurrentPosition(int syncmode) throws BitstreamException369{370int read = readBytes(syncbuf, 0, 4);371int headerstring = ((syncbuf[0] << 24) & 0xFF000000) | ((syncbuf[1] << 16) & 0x00FF0000) | ((syncbuf[2] << 8) & 0x0000FF00) | ((syncbuf[3] << 0) & 0x000000FF);372373try374{375source.unread(syncbuf, 0, read);376}377catch (IOException ex)378{379}380381boolean sync = false;382switch (read)383{384case 0:385sync = true;386break;387case 4:388sync = isSyncMark(headerstring, syncmode, syncword);389break;390}391392return sync;393}394395396// REVIEW: this class should provide inner classes to397// parse the frame contents. Eventually, readBits will398// be removed.399public int readBits(int n)400{401return get_bits(n);402}403404public int readCheckedBits(int n)405{406// REVIEW: implement CRC check.407return get_bits(n);408}409410protected BitstreamException newBitstreamException(int errorcode)411{412return new BitstreamException(errorcode, null);413}414protected BitstreamException newBitstreamException(int errorcode, Throwable throwable)415{416return new BitstreamException(errorcode, throwable);417}418419/**420* Get next 32 bits from bitstream.421* They are stored in the headerstring.422* syncmod allows Synchro flag ID423* The returned value is False at the end of stream.424*/425426int syncHeader(byte syncmode) throws BitstreamException427{428boolean sync;429int headerstring;430// read additional 2 bytes431int bytesRead = readBytes(syncbuf, 0, 3);432433if (bytesRead!=3) throw newBitstreamException(STREAM_EOF, null);434435headerstring = ((syncbuf[0] << 16) & 0x00FF0000) | ((syncbuf[1] << 8) & 0x0000FF00) | ((syncbuf[2] << 0) & 0x000000FF);436437do438{439headerstring <<= 8;440441if (readBytes(syncbuf, 3, 1)!=1)442throw newBitstreamException(STREAM_EOF, null);443444headerstring |= (syncbuf[3] & 0x000000FF);445446sync = isSyncMark(headerstring, syncmode, syncword);447}448while (!sync);449450//current_frame_number++;451//if (last_frame_number < current_frame_number) last_frame_number = current_frame_number;452453return headerstring;454}455456public boolean isSyncMark(int headerstring, int syncmode, int word)457{458boolean sync = false;459460if (syncmode == INITIAL_SYNC)461{462//sync = ((headerstring & 0xFFF00000) == 0xFFF00000);463sync = ((headerstring & 0xFFE00000) == 0xFFE00000); // SZD: MPEG 2.5464}465else466{467sync = ((headerstring & 0xFFF80C00) == word) &&468(((headerstring & 0x000000C0) == 0x000000C0) == single_ch_mode);469}470471// filter out invalid sample rate472if (sync)473sync = (((headerstring >>> 10) & 3)!=3);474// filter out invalid layer475if (sync)476sync = (((headerstring >>> 17) & 3)!=0);477// filter out invalid version478if (sync)479sync = (((headerstring >>> 19) & 3)!=1);480481return sync;482}483484/**485* Reads the data for the next frame. The frame is not parsed486* until parse frame is called.487*/488int read_frame_data(int bytesize) throws BitstreamException489{490int numread = 0;491numread = readFully(frame_bytes, 0, bytesize);492framesize = bytesize;493wordpointer = -1;494bitindex = -1;495return numread;496}497498/**499* Parses the data previously read with read_frame_data().500*/501void parse_frame() throws BitstreamException502{503// Convert Bytes read to int504int b=0;505byte[] byteread = frame_bytes;506int bytesize = framesize;507508// Check ID3v1 TAG (True only if last frame).509//for (int t=0;t<(byteread.length)-2;t++)510//{511// if ((byteread[t]=='T') && (byteread[t+1]=='A') && (byteread[t+2]=='G'))512// {513// System.out.println("ID3v1 detected at offset "+t);514// throw newBitstreamException(INVALIDFRAME, null);515// }516//}517518for (int k=0;k<bytesize;k=k+4)519{520int convert = 0;521byte b0 = 0;522byte b1 = 0;523byte b2 = 0;524byte b3 = 0;525b0 = byteread[k];526if (k+1<bytesize) b1 = byteread[k+1];527if (k+2<bytesize) b2 = byteread[k+2];528if (k+3<bytesize) b3 = byteread[k+3];529framebuffer[b++] = ((b0 << 24) &0xFF000000) | ((b1 << 16) & 0x00FF0000) | ((b2 << 8) & 0x0000FF00) | (b3 & 0x000000FF);530}531wordpointer = 0;532bitindex = 0;533}534535/**536* Read bits from buffer into the lower bits of an unsigned int.537* The LSB contains the latest read bit of the stream.538* (1 <= number_of_bits <= 16)539*/540public int get_bits(int number_of_bits)541{542int returnvalue = 0;543int sum = bitindex + number_of_bits;544545// E.B546// There is a problem here, wordpointer could be -1 ?!547if (wordpointer < 0) wordpointer = 0;548// E.B : End.549550if (sum <= 32)551{552// all bits contained in *wordpointer553returnvalue = (framebuffer[wordpointer] >>> (32 - sum)) & bitmask[number_of_bits];554// returnvalue = (wordpointer[0] >> (32 - sum)) & bitmask[number_of_bits];555if ((bitindex += number_of_bits) == 32)556{557bitindex = 0;558wordpointer++; // added by me!559}560return returnvalue;561}562563// E.B : Check that ?564//((short[])&returnvalue)[0] = ((short[])wordpointer + 1)[0];565//wordpointer++; // Added by me!566//((short[])&returnvalue + 1)[0] = ((short[])wordpointer)[0];567int Right = (framebuffer[wordpointer] & 0x0000FFFF);568wordpointer++;569int Left = (framebuffer[wordpointer] & 0xFFFF0000);570returnvalue = ((Right << 16) & 0xFFFF0000) | ((Left >>> 16)& 0x0000FFFF);571572returnvalue >>>= 48 - sum; // returnvalue >>= 16 - (number_of_bits - (32 - bitindex))573returnvalue &= bitmask[number_of_bits];574bitindex = sum - 32;575return returnvalue;576}577578/**579* Set the word we want to sync the header to.580* In Big-Endian byte order581*/582void set_syncword(int syncword0)583{584syncword = syncword0 & 0xFFFFFF3F;585single_ch_mode = ((syncword0 & 0x000000C0) == 0x000000C0);586}587/**588* Reads the exact number of bytes from the source589* input stream into a byte array.590*591* @param b The byte array to read the specified number592* of bytes into.593* @param offs The index in the array where the first byte594* read should be stored.595* @param len the number of bytes to read.596*597* @exception BitstreamException is thrown if the specified598* number of bytes could not be read from the stream.599*/600private int readFully(byte[] b, int offs, int len)601throws BitstreamException602{603int nRead = 0;604try605{606while (len > 0)607{608int bytesread = source.read(b, offs, len);609if (bytesread == -1)610{611while (len-->0)612{613b[offs++] = 0;614}615break;616//throw newBitstreamException(UNEXPECTED_EOF, new EOFException());617}618nRead = nRead + bytesread;619offs += bytesread;620len -= bytesread;621}622}623catch (IOException ex)624{625throw newBitstreamException(STREAM_ERROR, ex);626}627return nRead;628}629630/**631* Similar to readFully, but doesn't throw exception when632* EOF is reached.633*/634private int readBytes(byte[] b, int offs, int len)635throws BitstreamException636{637int totalBytesRead = 0;638try639{640while (len > 0)641{642int bytesread = source.read(b, offs, len);643if (bytesread == -1)644{645break;646}647totalBytesRead += bytesread;648offs += bytesread;649len -= bytesread;650}651}652catch (IOException ex)653{654throw newBitstreamException(STREAM_ERROR, ex);655}656return totalBytesRead;657}658}659660661