package net.sf.fmj.media.codec.video;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.media.Buffer;
import javax.media.Codec;
import javax.media.Format;
import javax.media.format.RGBFormat;
import javax.media.format.VideoFormat;
import net.sf.fmj.media.AbstractCodec;
import net.sf.fmj.media.util.ImageToBuffer;
/**
* Base class for video codecs which use ImageIO to decode the images.
* @author Ken Larson
*
*/
public abstract class ImageIODecoder extends AbstractCodec implements Codec
{
private final String formatName;
public ImageIODecoder(String formatName)
{
super();
this.formatName = formatName;
if (!ImageIO.getImageReadersByFormatName(formatName).hasNext())
{ throw new RuntimeException("No ImageIO reader found for " + formatName);
}
}
@Override
public abstract Format[] getSupportedInputFormats();
private final Format[] supportedOutputFormats = new Format[] {
new RGBFormat(null, -1, Format.byteArray, -1.0f, -1, -1, -1, -1),
};
@Override
public Format[] getSupportedOutputFormats(Format input)
{
if (input == null)
return supportedOutputFormats;
final VideoFormat inputCast = (VideoFormat) input;
final Format[] result = new Format[] {
new RGBFormat(inputCast.getSize(), -1, Format.byteArray, inputCast.getFrameRate(), -1, -1, -1, -1)};
// TODO: we don't know the details of the output format (pixel masks, etc) until we actually parse one!
return result;
}
@Override
public Format setInputFormat(Format format)
{
final VideoFormat videoFormat = (VideoFormat) format;
if (videoFormat.getSize() == null)
return null; // must set a size.
// TODO: check VideoFormat and compatibility
return super.setInputFormat(format);
}
@Override
public int process(Buffer input, Buffer output)
{
if (!checkInputBuffer(input))
{
return BUFFER_PROCESSED_FAILED;
}
if (isEOM(input))
{
propagateEOM(output); // TODO: what about data? can there be any?
return BUFFER_PROCESSED_OK;
}
try
{
// TODO: this is very inefficient - it allocates a new byte array (or more) every time
final ByteArrayInputStream is = new ByteArrayInputStream((byte[]) input.getData(), input.getOffset(), input.getLength());
final BufferedImage image = ImageIO.read(is);
is.close();
final Buffer b = ImageToBuffer.createBuffer(image, ((VideoFormat) outputFormat).getFrameRate());
output.setData(b.getData());
output.setOffset(b.getOffset());
output.setLength(b.getLength());
output.setFormat(b.getFormat()); // TODO: this is a bit hacky, this format will be more specific than the actual set output format, because now we know what ImageIO gave us for a BufferedImage as far as pixel masks, etc.
return BUFFER_PROCESSED_OK;
}
catch (IOException e)
{ output.setDiscard(true);
output.setLength(0);
return BUFFER_PROCESSED_FAILED;
}
}
}