package net.sf.fmj.media.parser;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.BadHeaderException;
import javax.media.Buffer;
import javax.media.Format;
import javax.media.IncompatibleSourceException;
import javax.media.Track;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.protocol.PullDataSource;
import javax.media.protocol.PullSourceStream;
import net.sf.fmj.media.AbstractDemultiplexer;
import net.sf.fmj.media.AbstractTrack;
import net.sf.fmj.utility.LoggerSingleton;
/**
* Raw parser which can read from a PullDataSource. Input is passed unmodified to output.
* There is a similar class in com.sun.media.parser.
* @author Ken Larson
*
*/
public class RawPullStreamParser extends AbstractDemultiplexer
{
private static final Logger logger = LoggerSingleton.logger;
private ContentDescriptor[] supportedInputContentDescriptors = new ContentDescriptor[] {new ContentDescriptor(ContentDescriptor.RAW)};
private PullDataSource source;
private PullSourceStreamTrack[] tracks;
@Override
public ContentDescriptor[] getSupportedInputContentDescriptors()
{
return supportedInputContentDescriptors;
}
@Override
public Track[] getTracks() throws IOException, BadHeaderException
{
return tracks;
}
@Override
public void setSource(DataSource source) throws IOException, IncompatibleSourceException
{
if (!(source instanceof PullDataSource))
throw new IncompatibleSourceException();
this.source = (PullDataSource) source;
}
@Override
public void start() throws IOException
{
source.start();
final PullSourceStream[] streams = source.getStreams();
tracks = new PullSourceStreamTrack[streams.length];
for (int i = 0; i < streams.length; ++i)
{
tracks[i] = new PullSourceStreamTrack(streams[i]);
}
}
@Override
public void stop()
{
try
{
source.stop();
} catch (IOException e)
{
logger.log(Level.WARNING, "" + e, e);
}
}
private class PullSourceStreamTrack extends AbstractTrack
{
private final PullSourceStream stream;
public PullSourceStreamTrack(PullSourceStream stream)
{
super();
this.stream = stream;
}
@Override
public Format getFormat()
{
return stream.getContentDescriptor(); // TODO: why not stream.getFormat()?
}
@Override
public void readFrame(Buffer buffer)
{
final int BUFFER_SIZE = 10000; // TODO: how do we determine this size? Is this what the BufferControl control is for?
if (buffer.getData() == null)
buffer.setData(new byte[BUFFER_SIZE]);
byte[] bytes = (byte[]) buffer.getData();
// TODO: set other buffer fields, like format or sequenceNumber?
try
{
int result = stream.read(bytes, 0, bytes.length);
if (result < 0)
{ buffer.setEOM(true);
buffer.setLength(0);
return;
}
buffer.setLength(result);
buffer.setOffset(0);
} catch (IOException e)
{
buffer.setEOM(true); // TODO
buffer.setDiscard(true); // TODO
buffer.setLength(0);
logger.log(Level.WARNING, "" + e, e);
}
}
}
}