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