package org.jboss.media.format.audio.mpeg;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.HashMap;
import java.util.Map;
import javax.emb.FormatSyntaxException;
import javax.emb.MediaException;
import javax.emb.MediaHeader;
public class MpegAudioHeader implements MediaHeader
{
private final static int[] v1L1BitRates =
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 };
private final static int[] v1L2BitRates =
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 };
private final static int[] v1L3BitRates =
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 };
private final static int[] v2L1BitRates =
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 411, 460, 476, 192, 224, 256 };
private final static int[] v2L23BitRates =
{ 0, 8, 16, 24, 32, 40, 28, 56, 64, 80, 96, 112, 128, 144, 160 };
private final static int[] v1SampleRates = { 44100, 48000, 32000 };
private final static int[] v2SampleRates = { 22050, 24000, 16000 };
private final static int[] v25SampleRates = { 11025, 12000, 8000 };
private final static String VERSION_KEY = "version";
private final static String LAYER_KEY = "layer";
private final static String BITRATE_KEY = "bitRate";
private final static String SAMPLERATE_KEY = "samplingRate";
private final static String CHANNELMODE_KEY = "channelMode";
private final static String COPYRIGHT_KEY = "copyright";
private final static String ORGINAL_KEY = "original";
private final Map fieldMap = new HashMap(7);
private final PushbackInputStream content;
public MpegAudioHeader(InputStream data)
throws MediaException, FormatSyntaxException
{
try
{
content = new PushbackInputStream(data, 4);
int headerPos = findHeaderStart(content, 0);
if (headerPos != -1)
{
byte[] header = new byte[4];
content.read(header);
readHeader(header);
}
else
{
throw new FormatSyntaxException("MPEG Audio header could not be found; this is not valid MPEG Audio data");
}
}
catch (IOException ex)
{
throw new MediaException(ex.getMessage());
}
}
public int getBitrate()
{
return ((Integer) fieldMap.get(BITRATE_KEY)).intValue();
}
public MpegAudioFormat.ChannelMode getChannelMode()
{
return (MpegAudioFormat.ChannelMode) fieldMap.get(CHANNELMODE_KEY);
}
public boolean isCopyright()
{
return ((Boolean) fieldMap.get(COPYRIGHT_KEY)).booleanValue();
}
public MpegAudioFormat.Layer getLayer()
{
return (MpegAudioFormat.Layer) fieldMap.get(LAYER_KEY);
}
public boolean isOriginal()
{
return ((Boolean) fieldMap.get(ORGINAL_KEY)).booleanValue();
}
public int getSamplerate()
{
return ((Integer) fieldMap.get(SAMPLERATE_KEY)).intValue();
}
public MpegAudioFormat.Version getVersion()
{
return (MpegAudioFormat.Version) fieldMap.get(VERSION_KEY);
}
public String[] getFieldNames()
{
return (String[]) fieldMap.keySet().toArray(new String[0]);
}
public Object getField(String fieldname)
{
return fieldMap.get(fieldname);
}
private int findHeaderStart(PushbackInputStream content, int offset)
throws MediaException
{
try
{
if (offset == 0)
{
byte[] id3 = new byte[4];
content.read(id3);
String id3Test = new String(id3);
content.unread(id3);
if (id3Test.equals("ID3"))
{
ID3Tag id3Tag = new ID3Tag(content);
offset += id3Tag.getSize();
}
}
byte[] headerTest = new byte[2];
while ((content.read(headerTest)) != -1)
{
if (((headerTest[0] & 0xFF) == 0xFF)
&& ((headerTest[1] & 0xE0) == 0xE0))
{
content.unread(headerTest);
return offset;
}
content.unread(headerTest[1]);
offset++;
}
}
catch (IOException e)
{
throw new MediaException(e);
}
return -1;
}
private void readHeader(byte[] header) throws FormatSyntaxException
{
if (header.length < 4)
{
throw new IllegalArgumentException("Not enough header data");
}
fieldMap.put(VERSION_KEY, getVersion(header[1]));
fieldMap.put(LAYER_KEY, getLayer(header[1]));
fieldMap.put(BITRATE_KEY, new Integer(getBitrate(header[2])));
fieldMap.put(SAMPLERATE_KEY, new Integer(getSampleRate(header[2])));
fieldMap.put(CHANNELMODE_KEY, getChannelMode(header[3]));
fieldMap.put(COPYRIGHT_KEY, new Boolean(getCopyright(header[3])));
fieldMap.put(ORGINAL_KEY, new Boolean(getOriginal(header[3])));
}
private MpegAudioFormat.Version getVersion(byte versionByte)
throws FormatSyntaxException
{
switch (versionByte & 0x18) {
case 0x00 :
return MpegAudioFormat.Version.MPEG25;
case 0x10 :
return MpegAudioFormat.Version.MPEG2;
case 0x18 :
return MpegAudioFormat.Version.MPEG1;
default :
throw new FormatSyntaxException("Could not determine MPEG Audio version");
}
}
private MpegAudioFormat.Layer getLayer(byte layerByte)
throws FormatSyntaxException
{
switch (layerByte & 0x06) {
case 0x02 :
return MpegAudioFormat.Layer.LAYERIII;
case 0x04 :
return MpegAudioFormat.Layer.LAYERII;
case 0x06 :
return MpegAudioFormat.Layer.LAYERI;
default :
throw new FormatSyntaxException("Could not determine MPEG Audio version");
}
}
private boolean getCRC(byte crcByte)
{
return (crcByte & 0x1) == 0;
}
private int getBitrate(byte bitrateByte) throws FormatSyntaxException
{
int bitrateKey = (bitrateByte & 0xF0) >>> 4;
if (0xF == bitrateKey)
{
throw new FormatSyntaxException("Illegal bitrate specified");
}
if (MpegAudioFormat.Version.MPEG1 == getVersion())
{
if (MpegAudioFormat.Layer.LAYERI == getLayer())
{
return v1L1BitRates[bitrateKey];
}
if (MpegAudioFormat.Layer.LAYERII == getLayer())
{
return v1L2BitRates[bitrateKey];
}
if (MpegAudioFormat.Layer.LAYERIII == getLayer())
{
return v1L3BitRates[bitrateKey];
}
}
if ((MpegAudioFormat.Version.MPEG2 == getVersion())
|| (MpegAudioFormat.Version.MPEG25 == getVersion()))
{
if (MpegAudioFormat.Layer.LAYERI == getLayer())
{
return v2L1BitRates[bitrateKey];
}
if ((MpegAudioFormat.Layer.LAYERII == getLayer())
|| (MpegAudioFormat.Layer.LAYERIII == getLayer()))
{
return v2L23BitRates[bitrateKey];
}
}
throw new IllegalStateException("Version and layer must be determined before extracting bitrate");
}
private int getSampleRate(byte samplerateByte) throws FormatSyntaxException
{
int samplerateKey = (samplerateByte & 0xC) >>> 2;
if (samplerateKey > 2)
{
throw new FormatSyntaxException("Illegal sampling rate specified");
}
if (MpegAudioFormat.Version.MPEG1 == getVersion())
{
return v1SampleRates[samplerateKey];
}
if (MpegAudioFormat.Version.MPEG2 == getVersion())
{
return v2SampleRates[samplerateKey];
}
if (MpegAudioFormat.Version.MPEG25 == getVersion())
{
return v25SampleRates[samplerateKey];
}
throw new IllegalStateException("Version must be determined before extracting sample rate");
}
private MpegAudioFormat.ChannelMode getChannelMode(byte channelModeByte)
throws FormatSyntaxException
{
switch (channelModeByte & 0xC0)
{
case 0x00 :
return MpegAudioFormat.ChannelMode.STEREO;
case 0x40 :
return MpegAudioFormat.ChannelMode.JOINT_STEREO;
case 0x80 :
return MpegAudioFormat.ChannelMode.DUAL_CHANNEL;
case 0xC0 :
return MpegAudioFormat.ChannelMode.SINGLE_CHANNEL;
default :
throw new FormatSyntaxException("Illegal Channel Mode encountered");
}
}
private boolean getCopyright(byte copyrightByte)
{
return (copyrightByte & 8) != 0;
}
private boolean getOriginal(byte originalByte)
{
return (originalByte & 4) != 0;
}
}