Finally designed and put together a
fully working implementation, involving a custom blocking queue and 6 threads. I’ve tested it on Windows XP, OS X, and old Kubuntu Hardy. Windows and Mac both look amazing and run perfectly smooth. Unfortunately on Linux the video playback stutters a lot. At first I thought it was due to the GC. After integrating an impressive object pool design, the cause actually turned out to be the Java audio api.
I use the
audio playback position to determine when a frame should be displayed. Running a little test exposes how reliable this timer is.
import javax.sound.sampled.*;
public class AudioPositionTest {
public static void main(String[] args) throws LineUnavailableException {
AudioFormat audFmt = new AudioFormat(18900, 16, 2, true, true);
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audFmt);
SourceDataLine player = (SourceDataLine) AudioSystem.getLine(info);
player.open(audFmt);
player.start();
byte[] abBuf = new byte[2 * 400];
long lngTestLength = 20 * 1000; // 20 seconds
long lngTestStart = System.currentTimeMillis();
long lngTestEnd = lngTestStart + lngTestLength;
System.out.println(System.getProperty("os.name") + "\tJava " +
System.getProperty("java.version"));
StringBuilder sb = new StringBuilder(400);
while (System.currentTimeMillis() < lngTestEnd) {
player.write(abBuf, 0, abBuf.length);
long lngTime = System.currentTimeMillis();
long lngPos = player.getLongFramePosition();
sb.append(lngTime - lngTestStart);
sb.append('\t');
sb.append(lngPos);
System.out.println(sb);
sb.setLength(0);
Thread.yield();
}
player.stop();
player.close();
}
}
Graphing some of the output makes it pretty clear why Linux playback is choppy.
Since that isn’t going to work, my next test will involve registering a
listener for
start and stop events, and track playback time manually. Though I’m worried my time and the playback time are going to get out of sync.