package com.limelight.binding.video;
import com.limelight.LimeLog;
import com.limelight.nvstream.av.DecodeUnit;
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
import com.limelight.nvstream.av.video.VideoDepacketizer;
/**
* Abstract implementation of a video decoder.
* @author Iwan Timmer
*/
public abstract class AbstractVideoRenderer implements VideoDecoderRenderer {
private Thread thread;
private boolean running;
private int dataSize;
private long last;
private long endToEndLatency;
private long decodeLatency;
private long packets;
private long maxLatency;
public boolean debug;
@Override
public boolean start(final VideoDepacketizer depacketizer) {
last = System.currentTimeMillis();
thread = new Thread(new Runnable() {
@Override
public void run() {
while (running) {
try {
DecodeUnit decodeUnit = depacketizer.takeNextDecodeUnit();
long latency = System.currentTimeMillis()-decodeUnit.getReceiveTimestamp();
endToEndLatency += latency;
dataSize += decodeUnit.getDataLength();
decodeUnit(decodeUnit);
latency = System.currentTimeMillis()-decodeUnit.getReceiveTimestamp();
decodeLatency += latency;
if (latency>maxLatency)
maxLatency = latency;
if (debug && System.currentTimeMillis()>last+2000) {
int bitrate = (dataSize/2)/1024;
System.out.println("Video " + bitrate + "kB/s " + maxLatency + "ms");
maxLatency = 0;
dataSize = 0;
last = System.currentTimeMillis();
}
depacketizer.freeDecodeUnit(decodeUnit);
} catch (InterruptedException ex) { }
}
}
});
running = true;
thread.start();
return true;
}
@Override
public void stop() {
running = false;
thread.interrupt();
try {
thread.join();
} catch (InterruptedException ex) {
LimeLog.severe(ex.getMessage());
}
}
public abstract void decodeUnit(DecodeUnit decodeUnit);
@Override
public int getCapabilities() {
return 0;
}
@Override
public int getAverageEndToEndLatency() {
return (int) (endToEndLatency / packets);
}
@Override
public int getAverageDecoderLatency() {
return (int) (decodeLatency / packets);
}
}