Methods Summary |
---|
public void | abortPrefetch()
//multiplexer.close();
prefetching = false;
|
boolean | checkEnd(int idx)
synchronized (endMarkers) {
endMarkers[idx] = true;
for (int i = 0; i < endMarkers.length; i++) {
if (!endMarkers[i])
return false;
}
return true;
}
|
boolean | checkPrefetch(int idx)
synchronized (prefetchMarkers) {
prefetchMarkers[idx] = true;
for (int i = 0; i < prefetchMarkers.length; i++) {
if (!prefetchMarkers[i])
return false;
}
return true;
}
|
boolean | checkResetted(int idx)
synchronized (resettedMarkers) {
resettedMarkers[idx] = true;
for (int i = 0; i < resettedMarkers.length; i++) {
if (!resettedMarkers[i])
return false;
}
return true;
}
|
boolean | checkStopAtTime(int idx)
synchronized (stopAtTimeMarkers) {
stopAtTimeMarkers[idx] = true;
for (int i = 0; i < stopAtTimeMarkers.length; i++) {
if (!stopAtTimeMarkers[i])
return false;
}
return true;
}
|
public void | connectorPushed(com.sun.media.InputConnector ic)This is the main processing function. It is called when
one of the the upstream modules pushes a buffer to this module.
int idx = -1;
// Determine track index.
// Do some loop unrolling to find the track index since there's
// probably just 2 tracks.
if (ics[0] == ic)
idx = 0;
else if (ics[1] == ic)
idx = 1;
else {
for (int i = 2; i < ics.length; i++ ) {
if (ics[i] == ic) {
idx = i; break;
}
}
if (idx == -1) {
// Something is terribly wrong.
throw new RuntimeException("BasicMuxModule: unmatched input connector!");
}
}
// This weird looking while loop here is necessary.
// What we are trying to achieve here is to never return from
// connectorPush until we actually finish processing the buffer.
// If a preset stop time is reached, we'll keep looping here.
// Without this loop, we'll miss one valid buffer from the
// upstream module. This is indeed very tricky.
while (true) {
if (paused[idx]) {
// Not sure how efficient the synchronized block is.
// So I'm doing the check before entering into it.
// Another check is performed inside the block.
synchronized (pauseSync[idx]) {
try {
while (paused[idx] && !closed)
pauseSync[idx].wait();
} catch (Exception e) {}
}
}
// Check to see if we have reached the preset stop time.
// If so, we'll notify the player and then loop back to
// the pause above. That way, we won't go on to process
// the data.
if (stopTime > -1 && elapseTime[idx].value >= stopTime) {
paused[idx] = true;
if (checkStopAtTime(idx)) {
if (multiplexer instanceof Drainable)
((Drainable)multiplexer).drain();
doStop();
if (moduleListener != null)
moduleListener.stopAtTime(this);
}
} else
break; // We've checked the stop time and we can just
// move on.
}
Buffer buffer = ic.getValidBuffer();
int flags = buffer.getFlags();
int rc = 0;
// Check if we are in the resetted state.
if (resetted) {
// Check if the input buffer contains the zero-length
// flush flag.
if ((flags & Buffer.FLAG_FLUSH) != 0) {
// This causes a deadlock interacting with the sync mux.
// Pause the particular track.
//paused[idx] = true;
// If all tracks are resetted, then we are done.
if (checkResetted(idx)) {
resetted = false;
doStop();
if (moduleListener != null)
moduleListener.resetted(this);
}
}
// In the resetted state, we'll not pass any data to the
// multiplexer.
ic.readReport();
return;
}
if (failed || closed || buffer.isDiscard()) {
ic.readReport();
return;
}
if (PlaybackEngine.DEBUG) jmd.moduleIn(this, 0, buffer, true);
// Signal the engine if the marker bit is set.
if ((flags & Buffer.FLAG_SYSTEM_MARKER) != 0 &&
moduleListener != null) {
moduleListener.markedDataArrived(this, buffer);
flags = flags & ~Buffer.FLAG_SYSTEM_MARKER;
buffer.setFlags(flags );
}
// Flag to indicate if data is prerolled, then we don't
// need to process it any further.
boolean dataPrerolled = false;
Format format = buffer.getFormat();
if (format == null) {
// Something's weird, we'll just assume it's the previous
// format.
format = ic.getFormat();
buffer.setFormat(format);
}
// Update the elapse time for prerolling and checking the
// preset stop time.
if (elapseTime[idx].update(buffer.getLength(),
buffer.getTimeStamp(), format)) {
// If an elapse time can be computed.
// Check prerolling.
if (prerollTrack[idx]) {
long target = getMediaNanoseconds();
if (elapseTime[idx].value > target) {
// Done with prerolling.
if (format instanceof AudioFormat &&
AudioFormat.LINEAR.equals(format.getEncoding())) {
int remain = (int)ElapseTime.audioTimeToLen(
elapseTime[idx].value - target,
(AudioFormat)format);
int offset = buffer.getOffset() +
buffer.getLength() - remain;
if (offset >= 0) {
buffer.setOffset(offset);
buffer.setLength(remain);
}
}
prerollTrack[idx] = false;
elapseTime[idx].setValue(target);
} else {
dataPrerolled = true;
}
}
// Check the preset stop time.
if (stopTime > -1 && elapseTime[idx].value > stopTime &&
format instanceof AudioFormat) {
// Processing the full chunk will have exceeded the
// preset stop time. We'll cut the audio data.
long exceeded = elapseTime[idx].value - stopTime;
int exceededLen = (int)ElapseTime.audioTimeToLen(exceeded,
(AudioFormat)format);
if (buffer.getLength() > exceededLen)
buffer.setLength(buffer.getLength() - exceededLen);
}
}
// Report the frame behind time for the engine.
if (moduleListener != null && format instanceof VideoFormat) {
// Check to see if the frame is delayed.
long mt = getMediaNanoseconds();
// Let's bring the #'s back to milli seconds range.
long lateBy = mt/1000000L - buffer.getTimeStamp()/1000000L -
getLatency()/1000000L;
//System.err.println("lateBy = " + lateBy);
float fb = lateBy * frameRate / 1000f;
if (fb < 0)
fb = 0;
if (lastFramesBehind != fb &&
(flags & Buffer.FLAG_NO_DROP) == 0) {
moduleListener.framesBehind(this, fb, ic);
lastFramesBehind = fb;
}
//System.err.println("frames behind = " + fb);
}
do {
if (!dataPrerolled) {
try {
rc = multiplexer.process(buffer, idx);
} catch (Throwable e) {
Log.dumpStack(e);
if (moduleListener != null)
moduleListener.internalErrorOccurred(this);
}
// Update the frame rate
if ( rc == PlugIn.BUFFER_PROCESSED_OK &&
format == firstVideoFormat) {
if (format == rtpVideoFormat) {
if ((flags & Buffer.FLAG_RTP_MARKER) > 0)
framesPlayed++;
} else {
framesPlayed++;
}
}
} else {
rc = PlugIn.BUFFER_PROCESSED_OK;
}
if ((rc & PlugIn.PLUGIN_TERMINATED) != 0) {
failed = true;
if (moduleListener != null)
moduleListener.pluginTerminated(this);
ic.readReport();
return;
}
// If the module is prefetching, we'll need to check to see
// if the device has been prefetched.
if (prefetching &&
(!(multiplexer instanceof Prefetchable) ||
((Prefetchable)multiplexer).isPrefetched())) {
synchronized (prefetchSync) {
if (!started && prefetching && !resetted)
paused[idx] = true;
if (checkPrefetch(idx))
prefetching = false;
}
// Notify the engine prefetching is done.
if (!prefetching && moduleListener != null)
moduleListener.bufferPrefetched(this);
}
} while (!resetted && rc == PlugIn.INPUT_BUFFER_NOT_CONSUMED);
bitsWritten += buffer.getLength();
if (buffer.isEOM()) {
if (!resetted)
paused[idx] = true;
if (checkEnd(idx)) {
doStop();
if (moduleListener != null)
moduleListener.mediaEnded(this);
}
}
ic.readReport();
if (PlaybackEngine.DEBUG) jmd.moduleIn(this, 0, buffer, false);
|
public void | doClose()
multiplexer.close();
closed = true;
for (int i = 0; i < pauseSync.length; i++) {
synchronized (pauseSync[i]) {
pauseSync[i].notifyAll();
}
}
|
public void | doDealloc()
//multiplexer.close();
|
public void | doFailedPrefetch()
prefetching = false;
|
public boolean | doPrefetch()
if (! ((PlaybackEngine)controller).prefetchEnabled)
return true;
resetPrefetchMarkers();
prefetching = true;
resume();
return true;
|
public boolean | doRealize()
if (multiplexer == null || inputs == null)
return false;
try {
multiplexer.open();
} catch (ResourceUnavailableException e) {
return false;
}
prefetchMarkers = new boolean[ics.length];
endMarkers = new boolean[ics.length];
resettedMarkers = new boolean[ics.length];
stopAtTimeMarkers = new boolean[ics.length];
paused = new boolean[ics.length];
prerollTrack = new boolean[ics.length];
pauseSync = new Object[ics.length];
elapseTime = new ElapseTime[ics.length];
for (int i = 0; i < ics.length; i++) {
prerollTrack[i] = false;
pauseSync[i] = new Object();
elapseTime[i] = new ElapseTime();
}
pause();
return true;
|
public void | doStart()
super.doStart();
resetEndMarkers();
resetStopAtTimeMarkers();
started = true;
synchronized (prefetchSync) {
prefetching = false;
resume();
}
|
public void | doStop()
super.doStop();
started = false;
resetPrefetchMarkers();
prefetching = true;
|
public long | getBitsWritten()
return bitsWritten;
|
public java.lang.Object | getControl(java.lang.String s)
return multiplexer.getControl(s);
|
public java.lang.Object[] | getControls()
return multiplexer.getControls();
|
public javax.media.protocol.DataSource | getDataOutput()
return multiplexer.getDataOutput();
|
public int | getFramesPlayed()
return framesPlayed;
|
public javax.media.Multiplexer | getMultiplexer()
return multiplexer;
|
public boolean | isThreaded()
return false;
|
void | pause()Internally, this pauses the processing thread from pushing more
data into the multiplexer.
for (int i = 0; i < paused.length; i++)
paused[i] = true;
|
protected void | process()
|
public void | reset()
super.reset();
resetResettedMarkers();
prefetching = false;
|
public void | resetBitsWritten()
bitsWritten = 0;
|
void | resetEndMarkers()
synchronized (endMarkers) {
for (int i = 0; i < endMarkers.length; i++)
endMarkers[i] = false;
}
|
public void | resetFramesPlayed()
framesPlayed = 0;
|
void | resetPrefetchMarkers()
synchronized (prefetchMarkers) {
for (int i = 0; i < prefetchMarkers.length; i++)
prefetchMarkers[i] = false;
}
|
void | resetResettedMarkers()
synchronized (resettedMarkers) {
for (int i = 0; i < resettedMarkers.length; i++)
resettedMarkers[i] = false;
}
|
void | resetStopAtTimeMarkers()
synchronized (stopAtTimeMarkers) {
for (int i = 0; i < stopAtTimeMarkers.length; i++)
stopAtTimeMarkers[i] = false;
}
|
void | resume()Internally, this resumes the processing thread to push
data into the multiplexer.
for (int i = 0; i < pauseSync.length; i++) {
synchronized (pauseSync[i]) {
paused[i] = false;
pauseSync[i].notifyAll();
}
}
|
public void | setFormat(com.sun.media.Connector connector, javax.media.Format format)
if (format instanceof VideoFormat) {
float fr = ((VideoFormat)format).getFrameRate();
if (fr != VideoFormat.NOT_SPECIFIED)
frameRate = fr;
}
|
public void | setPreroll(long wanted, long actual)Enable prerolling.
super.setPreroll(wanted, actual);
for (int i = 0; i < elapseTime.length; i++) {
elapseTime[i].setValue(actual);
// There's a bug in the MPEG packetizer that prevents prerolling
// from working properly. The timestamps on the MPEG_RTP
// buffers do not corresponds to the media time set after
// a seek. So we're disabling prerolling for MPEG_RTP here.
if (inputs[i] instanceof AudioFormat &&
mpegAudio.matches(inputs[i])) {
prerollTrack[i] = false;
} else
prerollTrack[i] = true;
}
|
public void | triggerReset()
multiplexer.reset();
synchronized (prefetchSync) {
prefetching = false;
if (resetted)
resume();
}
|