Methods Summary |
---|
protected void | bufClear()
bufOffset = 0;
bufLength = 0;
|
protected void | bufFlush()
filePointer -= bufLength; // It is going to be incremented in write()
write(buf, 0, bufLength);
|
protected void | bufSkip(int size)
bufOffset += size;
bufLength += size;
filePointer += size;
|
protected void | bufWriteByte(byte value)
buf[bufOffset] = value;
bufOffset++;
bufLength++;
filePointer++;
|
protected void | bufWriteBytes(java.lang.String s)
byte [] bytes = s.getBytes();
bufWriteBytes(bytes);
|
protected void | bufWriteBytes(byte[] bytes)
System.arraycopy(bytes, 0,
buf, bufOffset, bytes.length);
bufOffset += bytes.length;
bufLength += bytes.length;
filePointer += bytes.length;
|
protected void | bufWriteInt(int value)
buf[bufOffset + 0] = (byte)((value >> 24) & 0xFF);
buf[bufOffset + 1] = (byte)((value >> 16) & 0xFF);
buf[bufOffset + 2] = (byte)((value >> 8) & 0xFF);
buf[bufOffset + 3] = (byte)((value >> 0) & 0xFF);
bufOffset += 4;
bufLength += 4;
filePointer += 4;
|
protected void | bufWriteIntLittleEndian(int value)
buf[bufOffset + 3] = (byte)((value >>> 24) & 0xFF);
buf[bufOffset + 2] = (byte)((value >>> 16) & 0xFF);
buf[bufOffset + 1] = (byte)((value >>> 8) & 0xFF);
buf[bufOffset + 0] = (byte)((value >>> 0) & 0xFF);
bufOffset += 4;
bufLength += 4;
filePointer += 4;
|
protected void | bufWriteShort(short value)
buf[bufOffset + 0] = (byte)((value >> 8) & 0xFF);
buf[bufOffset + 1] = (byte)((value >> 0) & 0xFF);
bufOffset += 2;
bufLength += 2;
filePointer += 2;
|
protected void | bufWriteShortLittleEndian(short value)
buf[bufOffset + 1] = (byte)((value >> 8) & 0xFF);
buf[bufOffset + 0] = (byte)((value >> 0) & 0xFF);
bufOffset += 2;
bufLength += 2;
filePointer += 2;
|
private boolean | checkReady()
if (readyToStart)
return true;
for (int i = 0; i < ready.length; i++) {
if (!ready[i])
return false;
}
readyToStart = true;
return true;
|
public void | close()
if (sth != null) {
writeFooter();
write(null, 0, -1);
}
for (int i = 0; i < mc.length; i++) {
if (mc[i] != null)
mc[i].close();
}
synchronized (dataLock) {
mClosed = true;
dataLock.notifyAll();
}
|
private boolean | compensateStart(javax.media.Buffer buffer, int trackID)
synchronized (dataLock) {
// This is the case when all the data have arrived, but
// some buffers should have been dropped. The following
// code throw away the buffers that are behind. For video,
// key frames are carefully considered.
if (dataReady) {
if (!firstBuffersDone[trackID]) {
if (buffer.getTimeStamp() < masterTime) {
// Drop this frame.
return false;
} else {
if (buffer.getFormat() instanceof VideoFormat) {
Format fmt = buffer.getFormat();
boolean isKey = (jpegFmt.matches(fmt) ||
mjpgFmt.matches(fmt) ||
rgbFmt.matches(fmt) ||
yuvFmt.matches(fmt));
if (isKey ||
(buffer.getFlags() & Buffer.FLAG_KEY_FRAME) != 0 ||
nonKeyCount[trackID]++ > 30) {
buffer.setTimeStamp(masterTime);
firstBuffersDone[trackID] = true;
} else
return false;
} else {
// For everything else, the media time has exceeded
// the master time, we reset the timestamps.
buffer.setTimeStamp(masterTime);
firstBuffersDone[trackID] = true;
}
// Check to see if all the first buffers are being
// compensated.
for (int i = 0; i < firstBuffersDone.length; i++) {
if (!firstBuffersDone[i])
return true;
}
startCompensated = true;
return true;
}
}
return true;
}
if (buffer.getTimeStamp() < 0) {
// At least one of the tracks have undefined timestamps,
// synchronization is deem to fail. We won't attempt any
// compensation.
startCompensated = true;
dataReady = true;
dataLock.notifyAll();
return true;
}
firstBuffers[trackID] = buffer;
// Check to see if all the buffers have arrived.
boolean done = true;
for (int i = 0; i < firstBuffers.length; i++) {
if (firstBuffers[i] == null)
done = false;
}
if (!done) {
// If not, we'll wait here until all the buffers have arrived.
while (!dataReady && !mClosed) {
try {
dataLock.wait();
} catch (Exception e) {}
}
if (mClosed || firstBuffers[trackID] == null) {
// We'll drop this buffer after being compensated for.
return false;
}
return true;
}
// The first buffers have all arrived.
// Find the master time. If audio is there, we
// use it. Otherwise, choose the smallest time to
// be the master time.
masterTime = firstBuffers[0].getTimeStamp();
for (int i = 0; i < firstBuffers.length; i++) {
if (firstBuffers[i].getFormat() instanceof AudioFormat) {
masterTime = firstBuffers[i].getTimeStamp();
break;
}
if (firstBuffers[i].getTimeStamp() < masterTime)
masterTime = firstBuffers[i].getTimeStamp();
}
// For times bigger than master time, sets it to the
// master time. If not, we need to drop the frame.
startCompensated = true;
for (int i = 0; i < firstBuffers.length; i++) {
if (firstBuffers[i].getTimeStamp() >= masterTime) {
firstBuffers[i].setTimeStamp(masterTime);
firstBuffersDone[i] = true;
} else {
firstBuffers[i] = null;
startCompensated = false;
}
}
// Release the lock and buffer waiting to be processed since
// all the initial buffers have arrived.
synchronized (dataLock) {
dataReady = true;
dataLock.notifyAll();
}
return (firstBuffers[trackID] != null);
} // dataLock.
|
protected int | doProcess(javax.media.Buffer buffer, int trackID)Local methods
// Simple mux - just write the contents of the buffer
byte [] data = (byte[]) buffer.getData();
int dataLen = buffer.getLength();
if (!buffer.isEOM())
write(data, buffer.getOffset(), dataLen);
return BUFFER_PROCESSED_OK;
|
public javax.media.protocol.DataSource | getDataOutput()
if (source == null) {
source = new BasicMuxDataSource(this, outputCD);
synchronized (sourceLock) {
sourceLock.notifyAll();
}
}
return source;
|
private long | getDuration(javax.media.Buffer buffer)
javax.media.format.AudioFormat format =
(javax.media.format.AudioFormat)buffer.getFormat();
long duration = format.computeDuration(buffer.getLength());
if (duration < 0)
return 0;
return duration;
|
public long | getMediaNanoseconds()
return clock.getMediaNanoseconds();
|
public javax.media.Time | getMediaTime()
return clock.getMediaTime();
|
public float | getRate()
return clock.getRate();
|
public javax.media.Time | getStopTime()
return clock.getStopTime();
|
long | getStreamSize()
return fileSize;
|
public javax.media.Format[] | getSupportedInputFormats()
return supportedInputs;
|
public javax.media.protocol.ContentDescriptor[] | getSupportedOutputContentDescriptors(javax.media.Format[] inputs)
return supportedOutputs;
|
public javax.media.Time | getSyncTime()
return clock.getSyncTime();
|
public javax.media.TimeBase | getTimeBase()
return clock.getTimeBase();
|
boolean | isEOS()
return eos;
|
public javax.media.Time | mapToTimeBase(javax.media.Time t)
return clock.mapToTimeBase(t);
|
boolean | needsSeekable()
return false;
|
public void | open()
int i;
firstBuffer = true;
firstBuffers = new Buffer[inputs.length];
firstBuffersDone = new boolean[inputs.length];
nonKeyCount = new int[inputs.length];
mediaTime = new long[inputs.length];
for (i = 0; i < inputs.length; i++) {
firstBuffers[i] = null;
firstBuffersDone[i] = false;
nonKeyCount[i] = 0;
mediaTime[i] = 0;
}
ready = new boolean[inputs.length];
resetReady();
int len = 0;
mc = new MonitorAdapter[inputs.length];
for (i = 0; i < inputs.length; i++) {
if (inputs[i] instanceof VideoFormat ||
inputs[i] instanceof AudioFormat) {
mc[i] = new MonitorAdapter(inputs[i], this);
if (mc[i] != null)
len++;
}
}
int j = 0;
controls = new Control[len + 1];
for (i = 0; i < mc.length; i++) {
if (mc[i] != null)
controls[j++] = mc[i];
}
controls[j] = swc;
|
public int | process(javax.media.Buffer buffer, int trackID)
if (buffer.isDiscard())
return BUFFER_PROCESSED_OK;
if (!isLiveData && (buffer.getFlags() & Buffer.FLAG_LIVE_DATA) > 0) {
isLiveData = true;
}
// Wait until the datasource is created, connected and started
while (source == null || !source.isConnected() || !source.isStarted()) {
synchronized (sourceLock) {
try {
sourceLock.wait(500);
} catch (InterruptedException ie) {
}
if (flushing) {
flushing = false;
buffer.setLength(0); // flush the buffer and dont process it
return BUFFER_PROCESSED_OK;
}
}
}
synchronized (this) {
if (firstBuffer) {
writeHeader();
firstBuffer = false;
}
}
if (numTracks > 1) {
// For buffers with RTP time stamps, we'll skip until
// we reach the buffers with non-zero time. That's
// when synchronization is possible.
if ((buffer.getFlags() & Buffer.FLAG_RTP_TIME) != 0) {
if (buffer.getTimeStamp() <= 0)
return BUFFER_PROCESSED_OK;
}
if (!startCompensated) {
if (!compensateStart(buffer, trackID)) {
// Drop the buffer.
return BUFFER_PROCESSED_OK;
}
}
}
updateClock(buffer, trackID);
if (mc[trackID] != null && mc[trackID].isEnabled())
mc[trackID].process(buffer);
int processResult = doProcess(buffer, trackID);
if (fileSizeLimitReached)
processResult |= PLUGIN_TERMINATED;
return processResult;
|
public boolean | requireTwoPass()sub classes should override this method and return true if
two passes are required to create the media file.
Two passes may be required for example to rearrange the media
file so that the resultant file is Streamable
return false;
|
public void | reset()
//firstBuffer = true;
for (int i = 0; i < mediaTime.length; i++) {
mediaTime[i] = 0;
if (mc[i] != null)
mc[i].reset();
}
timeBase.update();
resetReady();
synchronized (sourceLock) {
flushing = true;
sourceLock.notifyAll();
}
|
private void | resetReady()
for (int i = 0; i < ready.length; i++)
ready[i] = false;
readyToStart = false;
synchronized (startup) {
startup.notifyAll();
}
|
protected int | seek(int location)
if (source == null || !source.isConnected())
return location;
filePointer = stream.seek(location);
return filePointer;
|
public javax.media.protocol.ContentDescriptor | setContentDescriptor(javax.media.protocol.ContentDescriptor outputCD)
if (matches(outputCD, supportedOutputs) == null)
return null;
// create the datasource and set its output
// contentdescriptor
this.outputCD = outputCD;
return outputCD;
|
public javax.media.Format | setInputFormat(javax.media.Format format, int trackID)
inputs[trackID] = format;
return format;
|
public void | setMediaTime(javax.media.Time now)
synchronized (timeSetSync) {
clock.setMediaTime(now);
for (int i = 0; i < mediaTime.length; i++)
mediaTime[i] = now.getNanoseconds();
timeBase.update();
}
|
public int | setNumTracks(int numTracks)
this.numTracks = numTracks;
if (inputs == null)
inputs = new Format[numTracks];
else {
Format [] newInputs = new Format[numTracks];
for (int i=0; i < inputs.length; i++) {
newInputs[i] = inputs[i];
}
inputs = newInputs;
}
return numTracks;
|
public float | setRate(float factor)
if (factor == clock.getRate())
return factor;
return clock.setRate(1.0f);
|
public void | setStopTime(javax.media.Time stopTime)
clock.setStopTime(stopTime);
|
void | setStream(com.sun.media.multiplexer.BasicMux$BasicMuxPushStream ps)
stream = ps;
|
public void | setTimeBase(javax.media.TimeBase master)
if (master != timeBase)
throw new IncompatibleTimeBaseException();
|
public void | stop()
synchronized (timeSetSync){
if (!started) return;
started = false;
clock.stop();
timeBase.mediaStopped();
}
|
public void | syncStart(javax.media.Time at)
synchronized (timeSetSync){
if (started) return;
started = true;
clock.syncStart(at);
timeBase.mediaStarted();
systemStartTime = System.currentTimeMillis() * 1000000;
}
|
private void | updateClock(javax.media.Buffer buffer, int trackID)
// Initially (after reset), block until all the streams
// have arrived.
if (!readyToStart && numTracks > 1) {
synchronized (startup) {
ready[trackID] = true;
if (checkReady()) {
startup.notifyAll();
} else {
try {
// wait at most for 1 seconds.
while (!readyToStart)
startup.wait(1000);
} catch (Exception e) { }
}
}
}
// get the timestamp on the incoming buffer
long timestamp = buffer.getTimeStamp();
if (timestamp <= 0 && buffer.getFormat() instanceof AudioFormat) {
// If it's audio data and the time stamp is undefined,
// we'll compute from the audio duration.
timestamp = mediaTime[trackID];
mediaTime[trackID] += getDuration(buffer);
} else if (timestamp <= 0) {
// This is video with TIME_UNKNOWN.
mediaTime[trackID] = System.currentTimeMillis() * 1000000 -
systemStartTime;
} else
mediaTime[trackID] = timestamp;
timeBase.update();
|
protected int | write(byte[] data, int offset, int length)
if (source == null || !source.isConnected())
return length;
if (length > 0) {
filePointer += length;
if (filePointer > fileSize)
fileSize = filePointer;
if (fileSizeLimit > 0 && fileSize >= fileSizeLimit)
fileSizeLimitReached = true;
}
return stream.write(data, offset, length);
|
protected void | writeFooter()
|
protected void | writeHeader()
|