/* * Entagged Audio Tag library * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package entagged.audioformats.mp3.util; /** * Create a MPEG Frame object that represent a Mpeg frame in a mp3 file !! Contains an exception that should be modified !! $Id: MPEGFrame.java,v 1.7 2005/05/19 16:00:15 kikidonk Exp $ * * @author Rapha�l Slinckx (KiKiDonK) * @version v0.03 */ public class MPEGFrame { private byte[] mpegBytes; /** The version of this MPEG frame (see the constants) */ private int MPEGVersion; /** Bitrate of this frame */ private int bitrate; /** Channel Mode of this Frame (see constants) */ private int channelMode; /** Emphasis mode string */ private String emphasis; /** Flag indicating if this frame has padding byte */ private boolean hasPadding; /** Flag indicating if this frame contains copyrighted material */ private boolean isCopyrighted; /** Flag indicating if this frame contains original material */ private boolean isOriginal; /** Flag indicating if this frame is protected */ private boolean isProtected; /** Flag indicating if this is a valid MPEG Frame */ private boolean isValid; /** Contains the mpeg layer of this frame (see constants) */ private int layer; /** Mode Extension of this frame */ private String modeExtension; /** Sampling rate of this frame in kbps */ private int samplingRate; /** Constant holding the Dual Channel Stereo Mode */ public final static int CHANNEL_MODE_DUAL_CHANNEL = 2; /** Constant holding the Joint Stereo Mode */ public final static int CHANNEL_MODE_JOINT_STEREO = 1; /** Constant holding the Mono Mode */ public final static int CHANNEL_MODE_MONO = 3; /** Constant holding the Stereo Mode */ public final static int CHANNEL_MODE_STEREO = 0; /** Constant holding the Layer 1 value Mpeg frame */ public final static int LAYER_I = 3; /** Constant holding the Layer 2 value Mpeg frame */ public final static int LAYER_II = 2; /** Constant holding the Layer 3 value Mpeg frame */ public final static int LAYER_III = 1; /** Constant holding the Reserved Layer value Mpeg frame */ public final static int LAYER_RESERVED = 0; /** Constant holding the mpeg frame version 1 */ public final static int MPEG_VERSION_1 = 3; /** Constant holding the mpeg frame version 2 */ public final static int MPEG_VERSION_2 = 2; /** Constant holding the mpeg frame version 2.5 */ public final static int MPEG_VERSION_2_5 = 0; /** Constant holding the reserved mpeg frame */ public final static int MPEG_VERSION_RESERVED = 1; /** Constant table holding the different Mpeg versions allowed */ private final static int[] MPEGVersionTable = {MPEG_VERSION_2_5, MPEG_VERSION_RESERVED, MPEG_VERSION_2, MPEG_VERSION_1}; /** Constant table holding the different Mpeg versions allowed in a string representation */ private final static String[] MPEGVersionTable_String = {"MPEG Version 2.5", "reserved", "MPEG Version 2 (ISO/IEC 13818-3)", "MPEG Version 1 (ISO/IEC 11172-3)"}; /** Constant 3ple table that holds the bitrate in kbps for the given layer, mode and value */ private final static int[][][] bitrateTable = { //table { //V1 {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1}, //LI {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1}, //LII {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1} //LIII }, { //V2 {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1}, //LI {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1}, //LII {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1} //LIII } }; /** Constant table holding the channel modes allowed */ /*private final static int[] channelModeTable = ;Not currently used {CHANNEL_MODE_STEREO, CHANNEL_MODE_JOINT_STEREO, CHANNEL_MODE_DUAL_CHANNEL, CHANNEL_MODE_MONO}; */ /** Constant table holding the channel modes allowed in a string representation */ private final static String[] channelModeTable_String = {"Stereo", "Joint stereo (Stereo)", "Dual channel (2 mono channels)", "Single channel (Mono)"}; /** Constant table holding the names of the emphasis modes in a string representation */ private final static String[] emphasisTable = {"none", "50/15 ms", "reserved", "CCIT J.17"}; /** Constant table holding the Layer descriptions allowed */ private final static int[] layerDescriptionTable = {LAYER_RESERVED, LAYER_III, LAYER_II, LAYER_I}; /** Constant table holding the Layer descriptions allowed in a string representation */ private final static String[] layerDescriptionTable_String = {"reserved", "Layer III", "Layer II", "Layer I"}; /** Constant table holding the mode extensions for a given layer in a string representation */ private final static String[][] modeExtensionTable = { {"4-31", "8-31", "12-31", "16-31"}, //LI , LII {"off-off", "on-off", "off-on", "on-on"} //"intensity Stereo - MS Stereo" //LIII }; /** Constant table holding the sampling rate in Hz for a given Mpeg version */ private final static int[][] samplingRateTable = { //table {44100, 48000, 32000, 0}, //V1 {22050, 24000, 16000, 0}, //V2 {11025, 12000, 8000, 0} //V3 }; private final static int[] SAMPLE_NUMBERS = {-1, 1152, 1152, 384}; /** * Creates a new MPEG frame with the given bytre array and decodes its contents * * @param b the array of bytes representing this mpeg frame */ public MPEGFrame( byte[] b ) { this.mpegBytes = b; if ( isMPEGFrame() ) { MPEGVersion = MPEGVersion(); layer = layerDescription(); isProtected = isProtected(); bitrate = bitrate(); samplingRate = samplingRate(); hasPadding = hasPadding(); //privateBit(); channelMode = channelMode(); modeExtension = modeExtension(); isCopyrighted = isCopyrighted(); isOriginal = isOriginal(); emphasis = emphasis(); isValid = true; } else //Ce n'est pas un frame MPEG isValid = false; this.mpegBytes = null; } /** * Gets the bitrate attribute of the MPEGFrame object * * @return The bitrate value */ public int getBitrate() { return bitrate; } /** * Gets the channelMode attribute of the MPEGFrame object * * @return The channelMode value */ public int getChannelNumber() { switch(channelMode) { case CHANNEL_MODE_DUAL_CHANNEL: return 2; case CHANNEL_MODE_JOINT_STEREO: return 2; case CHANNEL_MODE_MONO: return 1; case CHANNEL_MODE_STEREO: return 2; } return 0; } public int getChannelMode() { return channelMode; } /** * Gets the layerVersion attribute of the MPEGFrame object * * @return The layerVersion value */ public int getLayerVersion() { return layer; } /** * Gets the mPEGVersion attribute of the MPEGFrame object * * @return The mPEGVersion value */ public int getMPEGVersion() { return MPEGVersion; } /** * Gets the paddingLength attribute of the MPEGFrame object * * @return The paddingLength value */ public int getPaddingLength() { if ( hasPadding && layer != LAYER_I) return 1; if ( hasPadding && layer == LAYER_I) return 4; return 0; } /** * Gets the samplingRate attribute of the MPEGFrame object * * @return The samplingRate value */ public int getSamplingRate() { return samplingRate; } /** * Verify if this frame is a valid one * * @return The isValid value */ public boolean isValid() { return isValid; } /* * Gets this frame length in bytes * * @return the length in bytes of this frame */ public int getFrameLength() { if (layer == LAYER_I) { return (12 * (getBitrate() * 1000) / getSamplingRate() + getPaddingLength()) * 4; } return 144 * (getBitrate() * 1000) / getSamplingRate() + getPaddingLength(); } public int getSampleNumber() { int sn = SAMPLE_NUMBERS[layer]; //if ( ( MPEGVersion == MPEGFrame.MPEG_VERSION_2 ) || ( MPEGVersion == MPEGFrame.MPEG_VERSION_2_5 ) && (layer == LAYER_III)) //sn = sn/2; return sn; } /** * The Mpeg version of this frame in a string representation * * @param i the int constant of the version * @return the string representation of the version */ public String MPEGVersionToString( int i ) { return MPEGVersionTable_String[i]; } /** * get a string representation of the channel mode of this frame * * @param i the constant holding the channel mode * @return the string representation of this mode */ public String channelModeToString( int i ) { return channelModeTable_String[i]; } /** * Get the string representation of the layer version given the constant representing it * * @param i the constant holding the layer information * @return the string representation of this layer version */ public String layerToString( int i ) { return layerDescriptionTable_String[i]; } /** * Creates a string representation of this mpeg frame * * @return the string representing this frame */ public String toString() { String output = "\n----MPEGFrame--------------------\n"; output += "MPEG Version: " + MPEGVersionToString( MPEGVersion ) + "\tLayer: " + layerToString( layer ) + "\n"; output += "Bitrate: " + bitrate + "\tSamp.Freq.: " + samplingRate + "\tChan.Mode: " + channelModeToString( channelMode ) + "\n"; output += "Mode Extension: " + modeExtension + "\tEmphasis: " + emphasis + "\n"; output += "Padding? " + hasPadding + "\tProtected? " + isProtected + "\tCopyright? " + isCopyrighted + "\tOriginal? " + isOriginal + "\n"; output += "--------------------------------"; return output; } /** * Gets the copyrighted attribute of the MPEGFrame object * * @return The copyrighted value */ private boolean isCopyrighted() { return ( (mpegBytes[3]&0x08) == 0x08); } /** * Gets the mPEGFrame attribute of the MPEGFrame object * * @return The mPEGFrame value */ private boolean isMPEGFrame() { return ( (mpegBytes[0]&0xFF) == 0xFF ) && ( (mpegBytes[1]&0xE0) == 0xE0 ); } /** * Gets the original attribute of the MPEGFrame object * * @return The original value */ private boolean isOriginal() { return (mpegBytes[3]&0x04) == 0x04; } /** * Gets the protected attribute of the MPEGFrame object * * @return The protected value */ private boolean isProtected() { return (mpegBytes[1]&0x01) == 0x00; } /** * get the Mpeg version of this frame as an int value (see constants) * * @return the int value describing the Mpeg version */ private int MPEGVersion() { //System.err.println("V.:"+mpegBytes[1]+"|"+(mpegBytes[1]&0x18)+"|"+((mpegBytes[1]&0x18) >>> 3)); int index = ((mpegBytes[1]&0x18) >>> 3); //System.err.println(MPEGVersionTable[index]); return MPEGVersionTable[index]; } /** * get the bitrate of this frame * * @return the bitrate in kbps */ private int bitrate() { int index3 = ((mpegBytes[2]&0xF0) >>> 4); int index1 = ( MPEGVersion == MPEG_VERSION_1 ) ? 0 : 1; int index2; if ( layer == LAYER_I ) index2 = 0; else if ( layer == LAYER_II ) index2 = 1; else index2 = 2; return bitrateTable[index1][index2][index3]; } /** * get the Mpeg channel mode of this frame as a constant (see constants) * * @return the constant holding the channel mode */ private int channelMode() { int index = ((mpegBytes[3]&0xC0) >>> 6); return index; } /** * Get the emphasis mode of this frame in a string representation * * @return the emphasis mode */ private String emphasis() { int index = (mpegBytes[3]&0x03); return emphasisTable[index]; } /** * Check wether this frame uses padding bytes * * @return a boolean indicating if this frame uses padding */ private boolean hasPadding() { return (mpegBytes[2]&0x02) == 0x02; } /** * Get the layer version of this frame as a constant int value (see constants) * * @return the layer version constant */ private int layerDescription() { int index = ((mpegBytes[1]&0x06) >>> 1); return layerDescriptionTable[index]; } /** * Gets the string representation of the mode extension of this frame * * @return mode extension of this frame */ private String modeExtension() { int index2 = ((mpegBytes[3]&0x30) >>> 4); int index1 = ( layer == LAYER_III ) ? 1 : 0; return modeExtensionTable[index1][index2]; } /** * get the sampling rate in Hz of this frame * * @return the sampling rate in Hz of this frame */ private int samplingRate() { int index2 = ((mpegBytes[2]&0x0c) >>> 2); int index1; if ( MPEGVersion == MPEG_VERSION_1 ) index1 = 0; else if ( MPEGVersion == MPEG_VERSION_2 ) index1 = 1; else index1 = 2; return samplingRateTable[index1][index2]; } }