jPSXdec is a cross-platform PlayStation 1 media decoder/converter.
Get the latest version here.

Sunday, February 7, 2010

Writing a Java-only Video Player

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);;

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("") + "\tJava " +
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);


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.