📄 mp3framereader.java
字号:
package streams.mp3;import java.io.*;import common.Bitmask;import common.Delay;/** * A helper class for reading individual frames from an * MP3 input stream. * <P> * For each frame the header is first read to determine * the framesize as well as the delay. Other information * such as the type, layer, bitrate and sampling frequency * is extracted in the process as well. * * @author Lars Samuelsson */public class MP3FrameReader { /** * MPEG 1 type */ public static final int MPEG1 = 3; /** * MPEG 2 type */ public static final int MPEG2 = 2; /** * MPEG 2.5 type */ public static final int MPEG25 = 0; /** * Layer I type */ public static final int LAYERI = 3; /** * Layer II type */ public static final int LAYERII = 2; /** * Layer III type */ public static final int LAYERIII = 1; // bitrate lookup table (0 free, -1 bad) kbit/s private int[][] bitrates = { {-1, 0, 0, 0, -1, 0, 0, 0}, {-1, 8, 32, 32, -1, 32, 32, 32}, {-1, 16, 48, 64, -1, 40, 48, 64}, {-1, 24, 56, 96, -1, 48, 56, 96}, {-1, 32, 64, 128, -1, 56, 64, 128}, {-1, 64, 80, 160, -1, 64, 80, 160}, {-1, 80, 96, 192, -1, 80, 96, 192}, {-1, 56, 112, 224, -1, 96, 112, 224}, {-1, 64, 128, 256, -1, 112, 128, 256}, {-1, 128, 160, 288, -1, 128, 160, 288}, {-1, 160, 192, 320, -1, 160, 192, 320}, {-1, 112, 224, 352, -1, 192, 224, 352}, {-1, 128, 256, 384, -1, 224, 256, 384}, {-1, 256, 320, 416, -1, 256, 320, 416}, {-1, 320, 384, 448, -1, 320, 384, 448}, {-1, -1, -1, -1, -1, -1, -1, -1} }; // frequency lookup (-1 bad) private int frequencies[][] = { {11025, -1, 22050, 44100}, {12000, -1, 24000, 48000}, { 8000, -1, 16000, 32000}, { -1, -1, -1, -1} }; private final int headerlength = 4; private byte[] header; private final int framesync = 2047; private int framesize, bitrate, frequency, type, layer; private Delay delay; private InputStream mp3input; /** * Creates a frame reader on the specified input stream. * * @param mp3input An input stream containing MP3 data */ public MP3FrameReader(InputStream mp3input) { this.mp3input = mp3input; } /** * Reads the next frame from the input stream until * the file ends or garbled data is found. * * The tag is considered garbled data as it has * nothing to do in a continous stream of MP3 frames. * * @return An MP3 frame or null if the end of the * file or a tag has been reached */ public byte[] nextFrame() throws IOException { byte[] frame = null; scanForSynch(); byte[] fakeHeader = read(headerlength-1); if(fakeHeader == null) { return null; } header = new byte[fakeHeader.length + 1]; header[0] = (byte)255; for (int i = 0; i < fakeHeader.length; i++) { header[i+1] = fakeHeader[i]; } try { if(decodeHeader(header)) { int datasize = framesize - header.length; frame = new byte[framesize]; System.arraycopy(header, 0, frame, 0, header.length); if(mp3input.read(frame, header.length, datasize) == -1) return null; } } catch(Exception e) { return null; // garbled data } return frame; } public void scanForSynch () throws IOException { int b = -1; while (((b = mp3input.read()) != 255) && (b != -1)) { //System.out.println("b: " + b); } } /** * Reads the given number of bytes from the stream. * * @param len The number of bytes to be read * @return The read bytes */ public byte[] read(int len) throws IOException { byte[] bytes = new byte[len]; mp3input.read(bytes); return bytes; } /** * Extracts type, layer, bitrate, frequency, framesize and * delay from the header. * <P> * <B>Header bits</B><BR> * <TABLE><TR> * <TD Align="Right"> 31 - 21 </TD> * <TD Align="Left"> frame sync (all set in a valid frame)</TD></TR> * <TD Align="Right"> 20 - 19 </TD> * <TD Align="Left"> MPEG audio version </TD></TR> * <TD Align="Right"> 18 - 17 </TD> * <TD Align="Left"> layer description </TD></TR> * <TD Align="Right"> 16 </TD> * <TD Align="Left"> protection bit </TD></TR> * <TD Align="Right"> 15 - 12 </TD> * <TD Align="Left"> bitrate index </TD></TR> * <TD Align="Right"> 11 - 10 </TD> * <TD Align="Left"> sampling rate frequency index </TD></TR> * <TD Align="Right"> 09 </TD> * <TD Align="Left"> padding bit </TD></TR> * <TD Align="Right"> 08 </TD> * <TD Align="Left"> private bit </TD></TR> * <TD Align="Right"> 07 - 06 </TD> * <TD Align="Left"> channel mode </TD></TR> * <TD Align="Right"> 05 - 04 </TD> * <TD Align="Left"> mode extension </TD></TR> * <TD Align="Right"> 03 </TD> * <TD Align="Left"> copyright bit </TD></TR> * <TD Align="Right"> 02 </TD> * <TD Align="Left"> original indication bit </TD></TR> * <TD Align="Right"> 01 - 00 </TD> * <TD Align="Left"> emphasis </TD></TR> * </TABLE> * * @param headerBytes A frame header to be decoded * @return true if this header could be decoded */ public boolean decodeHeader(byte[] headerBytes) { int x, y, pad; Bitmask header = new Bitmask(headerBytes); // all 11 bits are set in a valid frame if (header.get(21, 31) != framesync) { // System.out.println("[FrameReader]: Framesync failure."); return false; } type = header.get(19, 20); layer = header.get(17, 18); x = ((type & 0x01) << 2) + layer; y = header.get(12, 15); if(bitrates[y][x] < 0) { System.out.println("[FrameReader]: Bitrate failure."); return false; } bitrate = bitrates[y][x]; x = type; y = header.get(10, 11); if(frequencies[y][x] < 0) { System.out.println("[FrameReader]: Frequency failure."); return false; } frequency = frequencies[y][x]; pad = header.get(9); // System.out.print("Padding: "+pad); if(layer == LAYERI) framesize = (12 * bitrate * 1000 / frequency + pad) * 4; else framesize = 144 * bitrate * 1000 / frequency + pad; // delay = new Delay((double) framesize * (double) 8 / (double) bitrate * (double) 1000 / (double) 1024); // Matt's new non-messed delay calc, sorry about the retarded # of (double)s delay = new Delay((double)framesize * 8 * 1000 / bitrate / 1000); // System.out.println("Framesize: "+framesize+", Bitrate: "+bitrate+", Delay: "+delay.getMillis()+":"+delay.getNanos()); return true; } /** * Fetches the bitrate based on the last header read * * @return The current bitrate */ public int getBitrate() { return bitrate; } /** * Fetches the frequency based on the last header read * * @return The current frequency */ public int getFrequency() { return frequency; } /** * Fetches the type based on the last header read * * @return The current type */ public int getType() { return type; } /** * Fetches the layer based on the last header read * * @return The current layer */ public int getLayer() { return layer; } /** * Fetches the delay based on the last header read * * @return The current delay */ public Delay getDelay() { return delay; } /** * Fetches the frame size based on the last header read * * @return The current frame size */ public int getFrameSize() { return framesize; } /** * Fetches the last read header as an array of bytes * * @return the last read header */ public byte[] getHeader() { return header; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -