/**
*
*/
package net.sf.fmj.filtergraph;
import java.io.IOException;
import javax.media.Buffer;
import javax.media.Demultiplexer;
import javax.media.Format;
import javax.media.PlugInManager;
import javax.media.Track;
/**
* A node in a filter graph for a Demultiplexer.
* @author Ken Larson
*
*/
public class DemuxNode extends Node
{
private final Format inputFormat;
private final Demultiplexer demux;
/**
* Must have the same number of entries as dest.
*/
private Track[] tracks;
public long sequenceNumber = 0L; // TODO: 1 per track
public DemuxNode(Format format, Demultiplexer demux, Track[] tracks)
{
super(demux, 0, tracks.length);
for (int i = 0; i < tracks.length; ++i)
{ setOutputPin(i, new OutputPin(this, i, i));
}
this.inputFormat = format;
this.demux = demux;
this.setTracks(tracks);
}
@Override
public int getPlugInType()
{
return PlugInManager.DEMULTIPLEXER;
}
@Override
Format setPlugInInputFormat(InputPin pin, Format format)
{
throw new UnsupportedOperationException(); // format is fixed.
}
@Override
Format setPlugInOutputFormat(OutputPin pin, Format format)
{
throw new UnsupportedOperationException(); // track formats are fixed
}
@Override
public Node duplicate()
{
return propagateDuplicate(new DemuxNode(getInputFormat(), getDemux(), getTracks()));
}
public void setTracks(Track[] tracks)
{
this.tracks = tracks;
}
public Track[] getTracks()
{
return tracks;
}
@Override
public Format getInputFormat()
{
return inputFormat;
}
public Demultiplexer getDemux()
{
return demux;
}
@Override
public void start() throws IOException
{
getDemux().start(); // TODO: what if already started?
}
@Override
public void stop()
{
getDemux().stop();
}
@Override
public int process(final Buffer input, final int sourceTrackNumber, final int destTrackNumber, final int flags)
{
for (int i = 0; i < getTracks().length; ++i)
{
if (sourceTrackNumber >= 0 && i != sourceTrackNumber)
{ //nCast.setBuffer(i, null);
continue;
}
final Link destLink = getDestLink(i);
if (destLink == null)
{ //nCast.setBuffer(i, null);
continue;
}
if ((flags & FilterGraphProcessor.SUPPRESS_TRACK_READ) == 0)
{
// JMF re-uses the previous buffer
if (getOutputBuffer(i) == null)
{
setOutputBuffer(i, new Buffer());
}
final Buffer buffer1 = getOutputBuffer(i);
buffer1.setLength(0);
buffer1.setSequenceNumber(sequenceNumber++); // TODO: 1 seq # per track is needed
buffer1.setFlags(0); // clear all flags. TODO: does JMF do this? Or must the demux itself clear the flags?
// // It does not appear that JMF sets the timestamp to what it thinks it is going to be.
// although this is theoretically possible knowing the frame/buffer # and the framerate.
// according to the docs, Each track has a sequence number that is updated by the Demultiplexer for each frame
// however, the OggDemux does not do this, and it appears that JMF sets the sequence number before giving it to the demux.
// TODO: other fields to clear?
getTracks()[i].readFrame(buffer1);
if (buffer1.getFormat() == null)
buffer1.setFormat(getTracks()[i].getFormat()); // TODO: is this right? JMF appears to set the format in between demux track read adnd codec process.
}
}
return Demultiplexer.BUFFER_PROCESSED_OK; // not really meaningful here
}
}