package org.mobicents.media;
import java.io.Serializable;
/**
* Standard JMF class -- see <a href="http://java.sun.com/products/java-media/jmf/2.1.1/apidocs/javax/media/Buffer.html" target="_blank">this class in the JMF Javadoc</a>.
* Coding complete.
* An observation on the use of Buffer in JMF: it appears that a Buffer is not considered to be immutable as
* it is processed (by a Codec, etc). JMF will do things like swap the data of two Buffers, or when
* input is not consumed, update the offset and length.
* The result of this is that care needs to be taken in implementation code to clone buffers if a buffer
* is to be used for multiple things (like in a cloned DataSource).
* @author Ken Larson
*
*/
public class Buffer implements Serializable {
protected long timeStamp = -1L;
protected long duration = -1L;
protected Format format;
protected int flags = 0;
protected Object data = null;
protected Object header = null;
protected int length = 0;
protected int offset = 0;
protected BufferFactory factory;
protected long sequenceNumber = SEQUENCE_UNKNOWN;
public static final int FLAG_EOM = 1;
public static final int FLAG_DISCARD = 2;
public static final int FLAG_SILENCE = 4;
public static final int FLAG_SID = 8;
public static final int FLAG_KEY_FRAME = 16;
public static final int FLAG_NO_DROP = 32;
public static final int FLAG_NO_WAIT = 64;
public static final int FLAG_NO_SYNC = 96;
public static final int FLAG_SYSTEM_TIME = 128;
public static final int FLAG_RELATIVE_TIME = 256;
public static final int FLAG_FLUSH = 512;
public static final int FLAG_SYSTEM_MARKER = 1024;
public static final int FLAG_RTP_MARKER = 2048;
public static final int FLAG_RTP_TIME = 4096;
public static final int FLAG_BUF_OVERFLOWN = 8192;
public static final int FLAG_BUF_UNDERFLOWN = 16384;
public static final int FLAG_LIVE_DATA = 32768;
public static final long TIME_UNKNOWN = -1;
public static final long SEQUENCE_UNKNOWN = Long.MAX_VALUE - 1;
public Buffer() {
super();
}
public void setFactory(BufferFactory factory) {
this.factory = factory;
}
public Format getFormat() {
return format;
}
public void setFormat(Format format) {
this.format = format; // do not clone.
}
public int getFlags() {
return flags;
}
public void setFlags(int flags) {
this.flags = flags;
}
public boolean isEOM() {
return (this.flags & FLAG_EOM) != 0;
}
public void setEOM(boolean eom) {
if (eom) {
this.flags |= FLAG_EOM;
} else {
this.flags &= ~FLAG_EOM;
}
}
public boolean isDiscard() {
return (this.flags & FLAG_DISCARD) != 0;
}
public void setDiscard(boolean discard) {
if (discard) {
this.flags |= FLAG_DISCARD;
} else {
this.flags &= ~FLAG_DISCARD;
}
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Object getHeader() {
return header;
}
public void setHeader(Object header) {
this.header = header;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public long getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(long timeStamp) {
this.timeStamp = timeStamp;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public void setSequenceNumber(long number) {
this.sequenceNumber = number;
}
public long getSequenceNumber() {
return sequenceNumber;
}
public void copy(Buffer buffer) {
copy(buffer, false);
}
public void copy(Buffer buffer, boolean swapData) {
duration = buffer.duration;
flags = buffer.flags;
format = buffer.format; // do not clone.
header = buffer.header; // do not clone.
length = buffer.length;
offset = buffer.offset;
sequenceNumber = buffer.sequenceNumber;
timeStamp = buffer.timeStamp;
//factory = buffer.factory;
if (swapData) {
data = dupData(buffer.data, false);
} else {
data = buffer.data;
}
}
public Object clone() {
// behavior is not the same as copy(this, true).
// 1. unknown data types results in = copy of data.
// 2. header is cloned.
final Buffer result = new Buffer();
result.duration = duration;
result.flags = flags;
result.format = format; // do not clone.
result.header = dupData(header, true); // clone - TODO: 2nd parameter?
result.length = length;
result.offset = offset;
result.sequenceNumber = sequenceNumber;
result.timeStamp = timeStamp;
result.data = dupData(data, true);
result.factory = factory;
return result;
}
/**
* @param standardTypesOnly if true, only byte[], short[], and int[] are recognized. Otherwise, all primitive arrays recognized.
* @return data if type is not recognized.
*/
private static Object dupData(Object data, boolean standardTypesOnly) {
// TODO: should we recognize other types of arrays?
if (data == null) {
return null;
}
final Object result;
final int len;
if (!data.getClass().isArray()) {
throw new IllegalArgumentException();
} // TODO: is this right?
if (data.getClass() == byte[].class) {
len = ((byte[]) data).length;
result = new byte[len];
} else if (data.getClass() == int[].class) {
len = ((int[]) data).length;
result = new int[len];
} else if (data.getClass() == short[].class) {
len = ((short[]) data).length;
result = new short[len];
} else if (!standardTypesOnly && data.getClass() == float[].class) {
len = ((float[]) data).length;
result = new float[len];
} else if (!standardTypesOnly && data.getClass() == double[].class) {
len = ((double[]) data).length;
result = new double[len];
} else if (!standardTypesOnly && data.getClass() == boolean[].class) {
len = ((boolean[]) data).length;
result = new boolean[len];
} else if (!standardTypesOnly && data.getClass() == long[].class) {
len = ((long[]) data).length;
result = new long[len];
} else if (!standardTypesOnly && data.getClass() == char[].class) {
len = ((char[]) data).length;
result = new char[len];
} else {
return data; // this appears to be compatible.
//throw new IllegalArgumentException(); // TODO: support other types?
}
System.arraycopy(data, 0, result, 0, len);
return result;
}
@Override
public String toString() {
return "Buffer[fmt=" + this.format + ", timestamp=" + this.timeStamp +
", seq=" + this.sequenceNumber + ", size= " + (length - offset) +
"]";
}
public void dispose() {
if (factory != null) {
factory.deallocate(this);
}
}
}