Computer/프로그래밍
[JMF] Customized PushBufferStream 의 구현
alias
2007. 4. 23. 13:06
반응형
이전 Post에서 PushBufferedDataSource를 확장한 DataSource에 대해서 살펴 보았다.
이전 Post에서 이야기 됬던 것처럼 실제로 DataSource에서 중요한 것은 PushBufferStream을 구현하는 것이다. 썬 홈페이지에 나온 LiveStream 의 구현을 보자.
중요한 부분은 read함수 부분이다. Buffer라는 클래스에 해당 데이터를 채우는 부분으로 실제 Bitmap관련 데이터 설정과 프레임 레이트 계산 및 설정 시퀀스 설정등이 있는 것을 알수 있다.
------------------------------------------------------------------------------
public class LiveStream implements PushBufferStream, Runnable {
protected ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW);
protected int maxDataLength;
protected byte [] data;
protected Dimension size;
protected RGBFormat rgbFormat;
protected AudioFormat audioFormat;
protected boolean started;
protected Thread thread;
protected float frameRate = 20f;
protected BufferTransferHandler transferHandler;
protected Control [] controls = new Control[0];
protected boolean videoData = true;
public LiveStream() {
if (videoData) {
int x, y, pos, revpos;
size = new Dimension(320, 240);
maxDataLength = size.width * size.height * 3;
rgbFormat = new RGBFormat(size, maxDataLength,
Format.byteArray,
frameRate,
24,
3, 2, 1,
3, size.width * 3,
VideoFormat.FALSE,
Format.NOT_SPECIFIED);
// generate the data 실제 데이터 생성
data = new byte[maxDataLength];
pos = 0;
revpos = (size.height - 1) * size.width * 3;
for (y = 0; y < size.height / 2; y++) {
for (x = 0; x < size.width; x++) {
byte value = (byte) ((y*2) & 0xFF);
data[pos++] = value;
data[pos++] = 0;
data[pos++] = 0;
data[revpos++] = value;
data[revpos++] = 0;
data[revpos++] = 0;
}
revpos -= size.width * 6;
}
} else { // audio data
audioFormat = new AudioFormat(AudioFormat.LINEAR,
8000.0,
8,
1,
Format.NOT_SPECIFIED,
AudioFormat.SIGNED,
8,
Format.NOT_SPECIFIED,
Format.byteArray);
maxDataLength = 1000;
}
thread = new Thread(this);
}
public ContentDescriptor getContentDescriptor() {
return cd;
}
public long getContentLength() {
return LENGTH_UNKNOWN;
}
public boolean endOfStream() {
return false;
}
int seqNo = 0;
double freq = 2.0;
public Format getFormat() {
if (videoData) return rgbFormat;
else return audioFormat;
}
public void read(Buffer buffer) throws IOException {
synchronized (this) {
Object outdata = buffer.getData();
if (outdata == null || !(outdata.getClass() == Format.byteArray) ||
((byte[])outdata).length < maxDataLength) {
outdata = new byte[maxDataLength];
buffer.setData(outdata);
}
if (videoData) {
buffer.setFormat( rgbFormat );
buffer.setTimeStamp( (long) (seqNo * (1000 / frameRate) * 1000000) );
int lineNo = (seqNo * 2) % size.height;
int chunkStart = lineNo * size.width * 3;
System.arraycopy(data, chunkStart,outdata,0,maxDataLength - (chunkStart));
if (chunkStart != 0) {
System.arraycopy(data, 0,
outdata, maxDataLength - chunkStart,
chunkStart);
}
} else {
buffer.setFormat( audioFormat );
buffer.setTimeStamp( 1000000000 / 8 );
for (int i = 0; i < 1000; i++) {
((byte[])outdata)[i] = (byte) (Math.sin(i / freq) * 32);
freq = (freq + 0.01);
if (freq > 10.0)
freq = 2.0;
}
}
buffer.setSequenceNumber( seqNo );
buffer.setLength(maxDataLength);
buffer.setFlags(0);
buffer.setHeader( null );
seqNo++;
}
}
public void setTransferHandler(BufferTransferHandler transferHandler) {
synchronized (this) {
this.transferHandler = transferHandler;
notifyAll();
}
}
void start(boolean started) {
synchronized ( this ) {
this.started = started;
if (started && !thread.isAlive()) {
thread = new Thread(this);
thread.start();
}
notifyAll();
}
}
public void run() {
while (started) {
synchronized (this) {
while (transferHandler == null && started) {
try {
wait(1000);
} catch (InterruptedException ie) {
}
} // while
}
if (started && transferHandler != null) {
transferHandler.transferData(this);
try {
Thread.currentThread().sleep( 10 );
} catch (InterruptedException ise) {
}
}
} // while (started)
} // run
public Object [] getControls() {
return controls;
}
public Object getControl(String controlType) {
try {
Class cls = Class.forName(controlType);
Object cs[] = getControls();
for (int i = 0; i < cs.length; i++) {
if (cls.isInstance(cs[i]))
return cs[i];
}
return null;
} catch (Exception e) { // no such controlType or such control
return null;
}
}
}
이전 Post에서 이야기 됬던 것처럼 실제로 DataSource에서 중요한 것은 PushBufferStream을 구현하는 것이다. 썬 홈페이지에 나온 LiveStream 의 구현을 보자.
중요한 부분은 read함수 부분이다. Buffer라는 클래스에 해당 데이터를 채우는 부분으로 실제 Bitmap관련 데이터 설정과 프레임 레이트 계산 및 설정 시퀀스 설정등이 있는 것을 알수 있다.
------------------------------------------------------------------------------
public class LiveStream implements PushBufferStream, Runnable {
protected ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW);
protected int maxDataLength;
protected byte [] data;
protected Dimension size;
protected RGBFormat rgbFormat;
protected AudioFormat audioFormat;
protected boolean started;
protected Thread thread;
protected float frameRate = 20f;
protected BufferTransferHandler transferHandler;
protected Control [] controls = new Control[0];
protected boolean videoData = true;
public LiveStream() {
if (videoData) {
int x, y, pos, revpos;
size = new Dimension(320, 240);
maxDataLength = size.width * size.height * 3;
rgbFormat = new RGBFormat(size, maxDataLength,
Format.byteArray,
frameRate,
24,
3, 2, 1,
3, size.width * 3,
VideoFormat.FALSE,
Format.NOT_SPECIFIED);
// generate the data 실제 데이터 생성
data = new byte[maxDataLength];
pos = 0;
revpos = (size.height - 1) * size.width * 3;
for (y = 0; y < size.height / 2; y++) {
for (x = 0; x < size.width; x++) {
byte value = (byte) ((y*2) & 0xFF);
data[pos++] = value;
data[pos++] = 0;
data[pos++] = 0;
data[revpos++] = value;
data[revpos++] = 0;
data[revpos++] = 0;
}
revpos -= size.width * 6;
}
} else { // audio data
audioFormat = new AudioFormat(AudioFormat.LINEAR,
8000.0,
8,
1,
Format.NOT_SPECIFIED,
AudioFormat.SIGNED,
8,
Format.NOT_SPECIFIED,
Format.byteArray);
maxDataLength = 1000;
}
thread = new Thread(this);
}
public ContentDescriptor getContentDescriptor() {
return cd;
}
public long getContentLength() {
return LENGTH_UNKNOWN;
}
public boolean endOfStream() {
return false;
}
int seqNo = 0;
double freq = 2.0;
public Format getFormat() {
if (videoData) return rgbFormat;
else return audioFormat;
}
public void read(Buffer buffer) throws IOException {
synchronized (this) {
Object outdata = buffer.getData();
if (outdata == null || !(outdata.getClass() == Format.byteArray) ||
((byte[])outdata).length < maxDataLength) {
outdata = new byte[maxDataLength];
buffer.setData(outdata);
}
if (videoData) {
buffer.setFormat( rgbFormat );
buffer.setTimeStamp( (long) (seqNo * (1000 / frameRate) * 1000000) );
int lineNo = (seqNo * 2) % size.height;
int chunkStart = lineNo * size.width * 3;
System.arraycopy(data, chunkStart,outdata,0,maxDataLength - (chunkStart));
if (chunkStart != 0) {
System.arraycopy(data, 0,
outdata, maxDataLength - chunkStart,
chunkStart);
}
} else {
buffer.setFormat( audioFormat );
buffer.setTimeStamp( 1000000000 / 8 );
for (int i = 0; i < 1000; i++) {
((byte[])outdata)[i] = (byte) (Math.sin(i / freq) * 32);
freq = (freq + 0.01);
if (freq > 10.0)
freq = 2.0;
}
}
buffer.setSequenceNumber( seqNo );
buffer.setLength(maxDataLength);
buffer.setFlags(0);
buffer.setHeader( null );
seqNo++;
}
}
public void setTransferHandler(BufferTransferHandler transferHandler) {
synchronized (this) {
this.transferHandler = transferHandler;
notifyAll();
}
}
void start(boolean started) {
synchronized ( this ) {
this.started = started;
if (started && !thread.isAlive()) {
thread = new Thread(this);
thread.start();
}
notifyAll();
}
}
public void run() {
while (started) {
synchronized (this) {
while (transferHandler == null && started) {
try {
wait(1000);
} catch (InterruptedException ie) {
}
} // while
}
if (started && transferHandler != null) {
transferHandler.transferData(this);
try {
Thread.currentThread().sleep( 10 );
} catch (InterruptedException ise) {
}
}
} // while (started)
} // run
public Object [] getControls() {
return controls;
}
public Object getControl(String controlType) {
try {
Class cls = Class.forName(controlType);
Object cs[] = getControls();
for (int i = 0; i < cs.length; i++) {
if (cls.isInstance(cs[i]))
return cs[i];
}
return null;
} catch (Exception e) { // no such controlType or such control
return null;
}
}
}
반응형