net.sf.fmj.utility.FormatArgUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fmj Show documentation
Show all versions of fmj Show documentation
Freedom for Media in Java
package net.sf.fmj.utility;
import java.awt.*;
import java.text.*;
import java.util.*;
import java.util.List;
import javax.media.Format;
import javax.media.format.*;
import net.sf.fmj.media.*;
import net.sf.fmj.media.format.*;
/**
* A class for converting Format objects to and from strings that can be used as
* arguments in command-line programs, or as parameters in URLs.
*
* The syntax is this: all elements are separated by a colon. Everything is
* uppercase by default, but case is ignored. Only thing that is lowercase is x
* in dimension. Generally, each item corresponds to a constructor argument. The
* Format subclass is inferred from the encoding. ? is used to indicate
* Format.NOT_SPECIFIED (-1). floating point values in audio formats are done as
* integers. In audio formats, Big endian is B, little endian is L, signed is S,
* unsigned is U Data types: B is byte[], S is short[], I is int[] Dimension:
* [width]x[height], like "640x480" Trailing not specified values may be
* omitted.
*
* new AudioFormat(AudioFormat.LINEAR, 44100.0, 16, 2) would be
* LINEAR:44100:16:2
*
*
*
* TODO: support WavAudioFormat, video formats, and other missing audio formats.
*
* @author Ken Larson
*
*/
public class FormatArgUtils
{
private static class Tokens
{
private final String[] items;
private int ix;
public Tokens(String[] items)
{
super();
this.items = items;
ix = 0;
}
public Class nextDataType() throws ParseException
{
String s = nextString();
if (s == null)
return null;
if (s.equals(NOT_SPECIFIED))
return null;
s = s.toUpperCase();
if (s.equals(BYTE_ARRAY))
return Format.byteArray;
else if (s.equals(SHORT_ARRAY))
return Format.shortArray;
else if (s.equals(INT_ARRAY))
return Format.intArray;
else
throw new ParseException("Expected one of [" + BYTE_ARRAY + ","
+ SHORT_ARRAY + "," + INT_ARRAY + "]: " + s, -1);
}
public Dimension nextDimension() throws ParseException
{
String s = nextString();
if (s == null)
return null;
if (s.equals(NOT_SPECIFIED))
return null;
s = s.toUpperCase();
String[] strings = s.split("X");
if (strings.length != 2)
throw new ParseException("Expected WIDTHxHEIGHT: " + s, -1);
int width;
int height;
try
{
width = Integer.parseInt(strings[0]);
} catch (NumberFormatException e)
{
throw new ParseException("Expected integer: " + strings[0], -1);
}
try
{
height = Integer.parseInt(strings[1]);
} catch (NumberFormatException e)
{
throw new ParseException("Expected integer: " + strings[1], -1);
}
return new Dimension(width, height);
}
public double nextDouble() throws ParseException
{
final String s = nextString();
if (s == null)
return Format.NOT_SPECIFIED;
if (s.equals(NOT_SPECIFIED))
return Format.NOT_SPECIFIED;
try
{
return Double.parseDouble(s);
} catch (NumberFormatException e)
{
throw new ParseException("Expected double: " + s, -1);
}
}
public int nextEndian() throws ParseException
{
String s = nextString();
if (s == null)
return Format.NOT_SPECIFIED;
if (s.equals(NOT_SPECIFIED))
return Format.NOT_SPECIFIED;
s = s.toUpperCase();
if (s.equals(BIG_ENDIAN))
return AudioFormat.BIG_ENDIAN;
else if (s.equals(LITTLE_ENDIAN))
return AudioFormat.LITTLE_ENDIAN;
else
throw new ParseException("Expected one of [" + BIG_ENDIAN + ","
+ LITTLE_ENDIAN + "]: " + s, -1);
}
public float nextFloat() throws ParseException
{
final String s = nextString();
if (s == null)
return Format.NOT_SPECIFIED;
if (s.equals(NOT_SPECIFIED))
return Format.NOT_SPECIFIED;
try
{
return Float.parseFloat(s);
} catch (NumberFormatException e)
{
throw new ParseException("Expected float: " + s, -1);
}
}
public int nextInt() throws ParseException
{
final String s = nextString();
if (s == null)
return Format.NOT_SPECIFIED;
if (s.equals(NOT_SPECIFIED))
return Format.NOT_SPECIFIED;
try
{
return Integer.parseInt(s);
} catch (NumberFormatException e)
{
throw new ParseException("Expected integer: " + s, -1);
}
}
public int nextRGBFormatEndian() throws ParseException
{
String s = nextString();
if (s == null)
return Format.NOT_SPECIFIED;
if (s.equals(NOT_SPECIFIED))
return Format.NOT_SPECIFIED;
s = s.toUpperCase();
if (s.equals(BIG_ENDIAN))
return RGBFormat.BIG_ENDIAN;
else if (s.equals(LITTLE_ENDIAN))
return RGBFormat.LITTLE_ENDIAN;
else
throw new ParseException("Expected one of [" + BIG_ENDIAN + ","
+ LITTLE_ENDIAN + "]: " + s, -1);
}
public int nextSigned() throws ParseException
{
String s = nextString();
if (s == null)
return Format.NOT_SPECIFIED;
if (s.equals(NOT_SPECIFIED))
return Format.NOT_SPECIFIED;
s = s.toUpperCase();
if (s.equals(UNSIGNED))
return AudioFormat.UNSIGNED;
else if (s.equals(SIGNED))
return AudioFormat.SIGNED;
else
throw new ParseException("Expected one of [" + UNSIGNED + ","
+ UNSIGNED + "]: " + s, -1);
}
public String nextString()
{
return nextString(null);
}
public String nextString(String defaultResult)
{
if (ix >= items.length)
return defaultResult;
final String result = items[ix];
++ix;
return result;
}
}
private static final char SEP = ':';
public static final String BYTE_ARRAY = "B";
public static final String SHORT_ARRAY = "S";
public static final String INT_ARRAY = "I";
public static final String NOT_SPECIFIED = "?";
// audio format constants:
public static final String BIG_ENDIAN = "B";
public static final String LITTLE_ENDIAN = "L";
public static final String SIGNED = "S";
public static final String UNSIGNED = "U";
private static final Map formatEncodings = new HashMap(); // corect
// case
private static final Map> formatClasses = new HashMap>();
static
{
buildFormatMap();
}
private static final void addAudioFormat(String s)
{
addFormat(s, AudioFormat.class);
}
private static final void addFormat(String s, Class clazz)
{
formatClasses.put(s.toLowerCase(), clazz);
formatEncodings.put(s.toLowerCase(), s);
}
private static final void addVideoFormat(String s)
{
addFormat(s, VideoFormat.class);
}
private static final void buildFormatMap()
{
addAudioFormat(AudioFormat.LINEAR);
addAudioFormat(AudioFormat.ULAW); // = "ULAW";
addAudioFormat(AudioFormat.ULAW_RTP); // = "ULAW/rtp";
addAudioFormat(AudioFormat.ALAW); // = "alaw"; // strange that this is
// lower case and ULAW is not...
addAudioFormat(AudioFormat.IMA4); // = "ima4";
addAudioFormat(AudioFormat.IMA4_MS); // = "ima4/ms";
addAudioFormat(AudioFormat.MSADPCM); // = "msadpcm";
addAudioFormat(AudioFormat.DVI); // = "dvi";
addAudioFormat(AudioFormat.DVI_RTP); // = "dvi/rtp";
addAudioFormat(AudioFormat.G723); // = "g723";
addAudioFormat(AudioFormat.G723_RTP); // = "g723/rtp";
addAudioFormat(AudioFormat.G728); // = "g728";
addAudioFormat(AudioFormat.G728_RTP); // = "g728/rtp";
addAudioFormat(AudioFormat.G729); // = "g729";
addAudioFormat(AudioFormat.G729_RTP); // = "g729/rtp";
addAudioFormat(AudioFormat.G729A); // = "g729a";
addAudioFormat(AudioFormat.G729A_RTP); // = "g729a/rtp";
addAudioFormat(AudioFormat.GSM); // = "gsm";
addAudioFormat(AudioFormat.GSM_MS); // = "gsm/ms";
addAudioFormat(AudioFormat.GSM_RTP); // = "gsm/rtp";
addAudioFormat(AudioFormat.MAC3); // = "MAC3";
addAudioFormat(AudioFormat.MAC6); // = "MAC6";
addAudioFormat(AudioFormat.TRUESPEECH); // = "truespeech";
addAudioFormat(AudioFormat.MSNAUDIO); // = "msnaudio";
addAudioFormat(AudioFormat.MPEGLAYER3); // = "mpeglayer3";
addAudioFormat(AudioFormat.VOXWAREAC8); // = "voxwareac8";
addAudioFormat(AudioFormat.VOXWAREAC10); // = "voxwareac10";
addAudioFormat(AudioFormat.VOXWAREAC16); // = "voxwareac16";
addAudioFormat(AudioFormat.VOXWAREAC20); // = "voxwareac20";
addAudioFormat(AudioFormat.VOXWAREMETAVOICE); // = "voxwaremetavoice";
addAudioFormat(AudioFormat.VOXWAREMETASOUND); // = "voxwaremetasound";
addAudioFormat(AudioFormat.VOXWARERT29H); // = "voxwarert29h";
addAudioFormat(AudioFormat.VOXWAREVR12); // = "voxwarevr12";
addAudioFormat(AudioFormat.VOXWAREVR18); // = "voxwarevr18";
addAudioFormat(AudioFormat.VOXWARETQ40); // = "voxwaretq40";
addAudioFormat(AudioFormat.VOXWARETQ60); // = "voxwaretq60";
addAudioFormat(AudioFormat.MSRT24); // = "msrt24";
addAudioFormat(AudioFormat.MPEG); // = "mpegaudio";
addAudioFormat(AudioFormat.MPEG_RTP); // = "mpegaudio/rtp";
addAudioFormat(AudioFormat.DOLBYAC3); // = "dolbyac3";
for (String e : BonusAudioFormatEncodings.ALL)
addAudioFormat(e);
// TODO: MpegEncoding using
// MpegEncoding.MPEG1L1,
// MpegEncoding.MPEG1L2,
// MpegEncoding.MPEG1L3,
// MpegEncoding.MPEG2DOT5L1,
// MpegEncoding.MPEG2DOT5L2,
// MpegEncoding.MPEG2DOT5L3,
// MpegEncoding.MPEG2L1,
// MpegEncoding.MPEG2L2,
// MpegEncoding.MPEG2L3,
// TODO: VorbisEncoding using VorbisEncoding.VORBISENC
// Video formats:
addVideoFormat(VideoFormat.CINEPAK); // ="cvid";
addFormat(VideoFormat.JPEG, JPEGFormat.class);
addVideoFormat(VideoFormat.JPEG_RTP); // ="jpeg/rtp";
addVideoFormat(VideoFormat.MPEG); // ="mpeg";
addVideoFormat(VideoFormat.MPEG_RTP); // ="mpeg/rtp";
addFormat(VideoFormat.H261, H261Format.class);
addVideoFormat(VideoFormat.H261_RTP); // ="h261/rtp";
addFormat(VideoFormat.H263, H263Format.class);
addVideoFormat(VideoFormat.H263_RTP); // ="h263/rtp";
addVideoFormat(VideoFormat.H263_1998_RTP); // ="h263-1998/rtp";
addFormat(VideoFormat.RGB, RGBFormat.class);
addFormat(VideoFormat.YUV, YUVFormat.class);
addFormat(VideoFormat.IRGB, IndexedColorFormat.class);
addVideoFormat(VideoFormat.SMC); // ="smc";
addVideoFormat(VideoFormat.RLE); // ="rle";
addVideoFormat(VideoFormat.RPZA); // ="rpza";
addVideoFormat(VideoFormat.MJPG); // ="mjpg";
addVideoFormat(VideoFormat.MJPEGA); // ="mjpa";
addVideoFormat(VideoFormat.MJPEGB); // ="mjpb";
addVideoFormat(VideoFormat.INDEO32); // ="iv32";
addVideoFormat(VideoFormat.INDEO41); // ="iv41";
addVideoFormat(VideoFormat.INDEO50); // ="iv50";
// TODO: AviVideoFormat
addFormat(BonusVideoFormatEncodings.GIF, GIFFormat.class);
addFormat(BonusVideoFormatEncodings.PNG, PNGFormat.class);
}
private static final String dataTypeToStr(Class clazz)
{
if (clazz == null)
{
return NOT_SPECIFIED;
}
if (clazz == Format.byteArray)
{
return BYTE_ARRAY;
}
if (clazz == Format.shortArray)
{
return SHORT_ARRAY;
}
if (clazz == Format.intArray)
{
return INT_ARRAY;
}
throw new IllegalArgumentException("" + clazz);
}
private static final String dimensionToStr(Dimension d)
{
if (d == null)
return NOT_SPECIFIED;
return ((int) d.getWidth()) + "x" + ((int) d.getHeight());
}
private static final String endianToStr(int endian)
{
if (endian == Format.NOT_SPECIFIED)
return NOT_SPECIFIED;
else if (endian == AudioFormat.BIG_ENDIAN)
return BIG_ENDIAN;
else if (endian == AudioFormat.LITTLE_ENDIAN)
return LITTLE_ENDIAN;
else
throw new IllegalArgumentException("Unknown endianness: " + endian);
}
private static final String floatToStr(float v)
{
if (v == Format.NOT_SPECIFIED)
return NOT_SPECIFIED;
else
return "" + v;
}
private static final String intToStr(int i)
{
if (i == Format.NOT_SPECIFIED)
return NOT_SPECIFIED;
else
return "" + i;
}
public static Format parse(String s) throws ParseException
{
final String[] strings = s.split("" + SEP);
final Tokens t = new Tokens(strings);
int ix = 0;
final String encodingIgnoreCase = t.nextString(null);
if (encodingIgnoreCase == null)
throw new ParseException("No encoding specified", 0);
final Class formatClass = formatClasses.get(encodingIgnoreCase
.toLowerCase());
if (formatClass == null)
throw new ParseException("Unknown encoding: " + encodingIgnoreCase,
-1);
final String encoding = formatEncodings.get(encodingIgnoreCase
.toLowerCase());
if (encoding == null)
throw new ParseException("Unknown encoding: " + encodingIgnoreCase,
-1);
if (AudioFormat.class.isAssignableFrom(formatClass))
{
final double sampleRate = t.nextDouble();
final int sampleSizeInBits = t.nextInt();
final int channels = t.nextInt();
final int endian = t.nextEndian();
final int signed = t.nextSigned();
final int frameSizeInBits = t.nextInt();
final double frameRate = t.nextDouble();
Class dataType = t.nextDataType();
if (dataType == null)
dataType = Format.byteArray; // default
return new AudioFormat(encoding, sampleRate, sampleSizeInBits,
channels, endian, signed, frameSizeInBits, frameRate,
dataType);
} else if (VideoFormat.class.isAssignableFrom(formatClass))
{
if (formatClass == JPEGFormat.class)
{
final java.awt.Dimension size = t.nextDimension();
final int maxDataLength = t.nextInt();
Class dataType = t.nextDataType();
if (dataType == null)
dataType = Format.byteArray; // default
final float frameRate = t.nextFloat();
final int q = Format.NOT_SPECIFIED; // TODO
final int dec = Format.NOT_SPECIFIED; // TODO
return new JPEGFormat(size, maxDataLength, dataType, frameRate,
q, dec);
} else if (formatClass == GIFFormat.class)
{
final java.awt.Dimension size = t.nextDimension();
final int maxDataLength = t.nextInt();
Class dataType = t.nextDataType();
if (dataType == null)
dataType = Format.byteArray; // default
final float frameRate = t.nextFloat();
return new GIFFormat(size, maxDataLength, dataType, frameRate);
} else if (formatClass == PNGFormat.class)
{
final java.awt.Dimension size = t.nextDimension();
final int maxDataLength = t.nextInt();
Class dataType = t.nextDataType();
if (dataType == null)
dataType = Format.byteArray; // default
final float frameRate = t.nextFloat();
return new PNGFormat(size, maxDataLength, dataType, frameRate);
} else if (formatClass == VideoFormat.class)
{
final java.awt.Dimension size = t.nextDimension();
final int maxDataLength = t.nextInt();
Class dataType = t.nextDataType();
if (dataType == null)
dataType = Format.byteArray; // default
final float frameRate = t.nextFloat();
return new VideoFormat(encoding, size, maxDataLength, dataType,
frameRate);
} else if (formatClass == RGBFormat.class)
{
final java.awt.Dimension size = t.nextDimension();
final int maxDataLength = t.nextInt();
Class dataType = t.nextDataType();
if (dataType == null)
dataType = Format.byteArray; // default
final float frameRate = t.nextFloat();
final int bitsPerPixel = t.nextInt();
final int red = t.nextInt();
final int green = t.nextInt();
final int blue = t.nextInt();
final int pixelStride = t.nextInt();
final int lineStride = t.nextInt();
final int flipped = t.nextInt();
final int endian = t.nextRGBFormatEndian();
if (pixelStride == -1 && lineStride == -1 && flipped == -1
&& endian == -1)
return new RGBFormat(size, maxDataLength, dataType,
frameRate, bitsPerPixel, red, green, blue);
return new RGBFormat(size, maxDataLength, dataType, frameRate,
bitsPerPixel, red, green, blue, pixelStride,
lineStride, flipped, endian);
}
// public RGBFormat(java.awt.Dimension size, int maxDataLength,
// Class dataType, float frameRate, int bitsPerPixel,
// int red, int green, int blue, int pixelStride, int lineStride,
// int flipped, int endian)
// TODO: others
throw new RuntimeException("TODO: Unknown class: " + formatClass);
} else
{
throw new RuntimeException("Unknown class: " + formatClass);
}
}
private static final String rgbFormatEndianToStr(int endian)
{
if (endian == Format.NOT_SPECIFIED)
return NOT_SPECIFIED;
else if (endian == RGBFormat.BIG_ENDIAN)
return BIG_ENDIAN;
else if (endian == RGBFormat.LITTLE_ENDIAN)
return LITTLE_ENDIAN;
else
throw new IllegalArgumentException("Unknown endianness: " + endian);
}
private static final String signedToStr(int signed)
{
if (signed == Format.NOT_SPECIFIED)
return NOT_SPECIFIED;
else if (signed == AudioFormat.SIGNED)
return SIGNED;
else if (signed == AudioFormat.UNSIGNED)
return UNSIGNED;
else
throw new IllegalArgumentException("Unknown signedness: " + signed);
}
public static String toString(Format f)
{
final List list = new ArrayList();
list.add(f.getEncoding().toUpperCase());
if (f instanceof AudioFormat)
{
final AudioFormat af = (AudioFormat) f;
list.add(intToStr((int) af.getSampleRate()));
list.add(intToStr(af.getSampleSizeInBits()));
list.add(intToStr(af.getChannels()));
list.add(endianToStr(af.getEndian()));
list.add(signedToStr(af.getSigned()));
list.add(intToStr(af.getFrameSizeInBits()));
list.add(intToStr((int) af.getFrameRate()));
if (af.getDataType() != null
&& af.getDataType() != Format.byteArray)
list.add(dataTypeToStr(af.getDataType()));
} else if (f instanceof VideoFormat)
{
final VideoFormat vf = (VideoFormat) f;
if (f.getClass() == JPEGFormat.class)
{
final JPEGFormat jf = (JPEGFormat) vf;
list.add(dimensionToStr(jf.getSize()));
list.add(intToStr(jf.getMaxDataLength()));
if (jf.getDataType() != null
&& jf.getDataType() != Format.byteArray)
list.add(dataTypeToStr(jf.getDataType()));
list.add(floatToStr(jf.getFrameRate()));
// TODO: Q, decimation
} else if (f.getClass() == GIFFormat.class)
{
final GIFFormat gf = (GIFFormat) vf;
list.add(dimensionToStr(gf.getSize()));
list.add(intToStr(gf.getMaxDataLength()));
if (gf.getDataType() != null
&& gf.getDataType() != Format.byteArray)
list.add(dataTypeToStr(gf.getDataType()));
list.add(floatToStr(gf.getFrameRate()));
} else if (f.getClass() == PNGFormat.class)
{
final PNGFormat pf = (PNGFormat) vf;
list.add(dimensionToStr(pf.getSize()));
list.add(intToStr(pf.getMaxDataLength()));
if (pf.getDataType() != null
&& pf.getDataType() != Format.byteArray)
list.add(dataTypeToStr(pf.getDataType()));
list.add(floatToStr(pf.getFrameRate()));
} else if (f.getClass() == VideoFormat.class)
{
list.add(dimensionToStr(vf.getSize()));
list.add(intToStr(vf.getMaxDataLength()));
if (vf.getDataType() != null
&& vf.getDataType() != Format.byteArray)
list.add(dataTypeToStr(vf.getDataType()));
list.add(floatToStr(vf.getFrameRate()));
} else if (f.getClass() == RGBFormat.class)
{
final RGBFormat rf = (RGBFormat) vf;
list.add(dimensionToStr(vf.getSize()));
list.add(intToStr(vf.getMaxDataLength()));
if (vf.getDataType() != null
&& vf.getDataType() != Format.byteArray)
list.add(dataTypeToStr(vf.getDataType()));
list.add(floatToStr(vf.getFrameRate()));
list.add(intToStr(rf.getBitsPerPixel()));
list.add(intToStr(rf.getRedMask())); // TODO: hex?
list.add(intToStr(rf.getGreenMask()));
list.add(intToStr(rf.getBlueMask()));
list.add(intToStr(rf.getPixelStride()));
list.add(intToStr(rf.getLineStride()));
list.add(intToStr(rf.getFlipped())); // TODO: use a string code
// for this?
list.add(rgbFormatEndianToStr(rf.getEndian()));
} else
throw new IllegalArgumentException(
"Unknown or unsupported format: " + f);
} else
{
throw new IllegalArgumentException("" + f);
}
// remove any default values from the end.
while (list.get(list.size() - 1) == null
|| list.get(list.size() - 1).equals(NOT_SPECIFIED))
list.remove(list.size() - 1);
final StringBuilder b = new StringBuilder();
for (int i = 0; i < list.size(); ++i)
{
if (i > 0)
b.append(SEP);
b.append(list.get(i));
}
return b.toString();
}
}