Remove pooling code due to higher concurrency latency that resulted in a net loss of performance.

This commit is contained in:
Cameron Gutman 2013-11-21 16:40:27 -05:00
parent 1d7460e8b3
commit 6bb215eddf
10 changed files with 11 additions and 201 deletions

View File

@ -4,8 +4,6 @@ import com.limelight.nvstream.NvConnection;
import com.limelight.nvstream.input.NvControllerPacket; import com.limelight.nvstream.input.NvControllerPacket;
import android.app.Activity; import android.app.Activity;
import android.content.ComponentCallbacks2;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.os.Bundle; import android.os.Bundle;
import android.view.InputDevice; import android.view.InputDevice;
@ -96,14 +94,6 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
super.onPause(); super.onPause();
} }
@Override
public void onTrimMemory(int trimLevel) {
if (trimLevel >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW)
{
conn.trim();
}
}
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {

View File

@ -10,7 +10,6 @@ import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import com.limelight.nvstream.av.AvByteBufferDescriptor; import com.limelight.nvstream.av.AvByteBufferDescriptor;
import com.limelight.nvstream.av.AvByteBufferPool;
import com.limelight.nvstream.av.AvRtpPacket; import com.limelight.nvstream.av.AvRtpPacket;
import com.limelight.nvstream.av.AvShortBufferDescriptor; import com.limelight.nvstream.av.AvShortBufferDescriptor;
import com.limelight.nvstream.av.audio.AvAudioDepacketizer; import com.limelight.nvstream.av.audio.AvAudioDepacketizer;
@ -34,8 +33,6 @@ public class NvAudioStream {
private LinkedList<Thread> threads = new LinkedList<Thread>(); private LinkedList<Thread> threads = new LinkedList<Thread>();
private AvByteBufferPool pool = new AvByteBufferPool(1500);
private boolean aborting = false; private boolean aborting = false;
public void abort() public void abort()
@ -105,11 +102,6 @@ public class NvAudioStream {
rtp.connect(InetAddress.getByName(host), RTP_PORT); rtp.connect(InetAddress.getByName(host), RTP_PORT);
} }
public void trim()
{
depacketizer.trim();
}
private void setupAudio() private void setupAudio()
{ {
int channelConfig; int channelConfig;
@ -166,8 +158,6 @@ public class NvAudioStream {
} }
depacketizer.decodeInputData(packet); depacketizer.decodeInputData(packet);
pool.free(packet.getBackingBuffer());
} }
} }
}; };
@ -193,8 +183,6 @@ public class NvAudioStream {
} }
track.write(samples.data, samples.offset, samples.length); track.write(samples.data, samples.offset, samples.length);
depacketizer.releaseBuffer(samples);
} }
} }
}; };
@ -208,7 +196,7 @@ public class NvAudioStream {
Thread t = new Thread() { Thread t = new Thread() {
@Override @Override
public void run() { public void run() {
DatagramPacket packet = new DatagramPacket(pool.allocate(), 1500); DatagramPacket packet = new DatagramPacket(new byte[1500], 1500);
AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0); AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0);
while (!isInterrupted()) while (!isInterrupted())
@ -228,7 +216,7 @@ public class NvAudioStream {
packets.add(new AvRtpPacket(desc)); packets.add(new AvRtpPacket(desc));
// Get a new buffer from the buffer pool // Get a new buffer from the buffer pool
packet.setData(pool.allocate(), 0, 1500); packet.setData(new byte[1500], 0, 1500);
} }
} }
}; };

View File

@ -112,12 +112,6 @@ public class NvConnection {
inputStream = null; inputStream = null;
} }
} }
public void trim()
{
videoStream.trim();
audioStream.trim();
}
public void start() public void start()
{ {

View File

@ -82,15 +82,10 @@ public class NvVideoStream {
threads.clear(); threads.clear();
} }
public void trim()
{
depacketizer.trim();
}
private void readFirstFrame(String host) throws IOException private void readFirstFrame(String host) throws IOException
{ {
byte[] firstFrame = depacketizer.allocatePacketBuffer(); byte[] firstFrame = new byte[1500];
System.out.println("VID: Waiting for first frame"); System.out.println("VID: Waiting for first frame");
firstFrameSocket = new Socket(host, FIRST_FRAME_PORT); firstFrameSocket = new Socket(host, FIRST_FRAME_PORT);
@ -220,8 +215,6 @@ public class NvVideoStream {
} }
decrend.submitDecodeUnit(du); decrend.submitDecodeUnit(du);
depacketizer.releaseDecodeUnit(du);
} }
} }
}; };
@ -262,7 +255,7 @@ public class NvVideoStream {
Thread t = new Thread() { Thread t = new Thread() {
@Override @Override
public void run() { public void run() {
DatagramPacket packet = new DatagramPacket(depacketizer.allocatePacketBuffer(), 1500); DatagramPacket packet = new DatagramPacket(new byte[1500], 1500);
AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0); AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0);
while (!isInterrupted()) while (!isInterrupted())
@ -282,7 +275,7 @@ public class NvVideoStream {
packets.add(new AvRtpPacket(desc)); packets.add(new AvRtpPacket(desc));
// Get a new buffer from the buffer pool // Get a new buffer from the buffer pool
packet.setData(depacketizer.allocatePacketBuffer(), 0, 1500); packet.setData(new byte[1500], 0, 1500);
} }
} }
}; };

View File

@ -4,7 +4,6 @@ public class AvByteBufferDescriptor {
public byte[] data; public byte[] data;
public int offset; public int offset;
public int length; public int length;
public Object context;
public AvByteBufferDescriptor(byte[] data, int offset, int length) public AvByteBufferDescriptor(byte[] data, int offset, int length)
{ {

View File

@ -1,35 +0,0 @@
package com.limelight.nvstream.av;
import java.util.LinkedList;
public class AvByteBufferPool {
private LinkedList<byte[]> bufferList = new LinkedList<byte[]>();
private int bufferSize;
public AvByteBufferPool(int size)
{
this.bufferSize = size;
}
public synchronized void purge()
{
this.bufferList = new LinkedList<byte[]>();
}
public synchronized byte[] allocate()
{
if (bufferList.isEmpty())
{
return new byte[bufferSize];
}
else
{
return bufferList.removeFirst();
}
}
public synchronized void free(byte[] buffer)
{
bufferList.addFirst(buffer);
}
}

View File

@ -1,35 +0,0 @@
package com.limelight.nvstream.av;
import java.util.LinkedList;
public class AvShortBufferPool {
private LinkedList<short[]> bufferList = new LinkedList<short[]>();
private int bufferSize;
public AvShortBufferPool(int size)
{
this.bufferSize = size;
}
public synchronized void purge()
{
this.bufferList = new LinkedList<short[]>();
}
public synchronized short[] allocate()
{
if (bufferList.isEmpty())
{
return new short[bufferSize];
}
else
{
return bufferList.removeFirst();
}
}
public synchronized void free(short[] buffer)
{
bufferList.addFirst(buffer);
}
}

View File

@ -5,26 +5,18 @@ import java.util.concurrent.LinkedBlockingQueue;
import com.limelight.nvstream.av.AvByteBufferDescriptor; import com.limelight.nvstream.av.AvByteBufferDescriptor;
import com.limelight.nvstream.av.AvRtpPacket; import com.limelight.nvstream.av.AvRtpPacket;
import com.limelight.nvstream.av.AvShortBufferDescriptor; import com.limelight.nvstream.av.AvShortBufferDescriptor;
import com.limelight.nvstream.av.AvShortBufferPool;
public class AvAudioDepacketizer { public class AvAudioDepacketizer {
private LinkedBlockingQueue<AvShortBufferDescriptor> decodedUnits = private LinkedBlockingQueue<AvShortBufferDescriptor> decodedUnits =
new LinkedBlockingQueue<AvShortBufferDescriptor>(15); new LinkedBlockingQueue<AvShortBufferDescriptor>(15);
private AvShortBufferPool pool = new AvShortBufferPool(OpusDecoder.getMaxOutputShorts());
// Sequencing state // Sequencing state
private short lastSequenceNumber; private short lastSequenceNumber;
public void trim()
{
pool.purge();
}
private void decodeData(byte[] data, int off, int len) private void decodeData(byte[] data, int off, int len)
{ {
// Submit this data to the decoder // Submit this data to the decoder
short[] pcmData = pool.allocate(); short[] pcmData = new short[OpusDecoder.getMaxOutputShorts()];
int decodeLen = OpusDecoder.decode(data, off, len, pcmData); int decodeLen = OpusDecoder.decode(data, off, len, pcmData);
if (decodeLen > 0) { if (decodeLen > 0) {
@ -32,14 +24,7 @@ public class AvAudioDepacketizer {
decodeLen *= OpusDecoder.getChannelCount(); decodeLen *= OpusDecoder.getChannelCount();
// Put it on the decoded queue // Put it on the decoded queue
if (!decodedUnits.offer(new AvShortBufferDescriptor(pcmData, 0, decodeLen))) decodedUnits.offer(new AvShortBufferDescriptor(pcmData, 0, decodeLen));
{
pool.free(pcmData);
}
}
else {
System.out.println("decode failed: "+decodeLen);
pool.free(pcmData);
} }
} }
@ -68,11 +53,6 @@ public class AvAudioDepacketizer {
decodeData(rtpPayload.data, rtpPayload.offset, rtpPayload.length); decodeData(rtpPayload.data, rtpPayload.offset, rtpPayload.length);
} }
public void releaseBuffer(AvShortBufferDescriptor decodedData)
{
pool.free(decodedData.data);
}
public AvShortBufferDescriptor getNextDecodedData() throws InterruptedException public AvShortBufferDescriptor getNextDecodedData() throws InterruptedException
{ {
return decodedUnits.take(); return decodedUnits.take();

View File

@ -4,7 +4,6 @@ import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import com.limelight.nvstream.av.AvByteBufferDescriptor; import com.limelight.nvstream.av.AvByteBufferDescriptor;
import com.limelight.nvstream.av.AvByteBufferPool;
import com.limelight.nvstream.av.AvDecodeUnit; import com.limelight.nvstream.av.AvDecodeUnit;
import com.limelight.nvstream.av.AvRtpPacket; import com.limelight.nvstream.av.AvRtpPacket;
@ -22,49 +21,12 @@ public class AvVideoDepacketizer {
private LinkedBlockingQueue<AvDecodeUnit> decodedUnits = new LinkedBlockingQueue<AvDecodeUnit>(); private LinkedBlockingQueue<AvDecodeUnit> decodedUnits = new LinkedBlockingQueue<AvDecodeUnit>();
private AvByteBufferPool pool = new AvByteBufferPool(1500);
public byte[] allocatePacketBuffer()
{
return pool.allocate();
}
public void trim()
{
pool.purge();
}
private void clearAvcNalState() private void clearAvcNalState()
{ {
if (avcNalDataChain != null)
{
for (AvByteBufferDescriptor avbb : avcNalDataChain)
{
AvVideoPacket packet = (AvVideoPacket) avbb.context;
if (packet.release() == 0) {
pool.free(avbb.data);
}
}
}
avcNalDataChain = null; avcNalDataChain = null;
avcNalDataLength = 0; avcNalDataLength = 0;
} }
public void releaseDecodeUnit(AvDecodeUnit decodeUnit)
{
// Remove the reference from each AvVideoPacket (freeing if okay)
for (AvByteBufferDescriptor buff : decodeUnit.getBufferList())
{
AvVideoPacket packet = (AvVideoPacket) buff.context;
if (packet.release() == 0) {
pool.free(buff.data);
}
}
}
private void reassembleAvcNal() private void reassembleAvcNal()
{ {
// This is the start of a new NAL // This is the start of a new NAL
@ -119,10 +81,7 @@ public class AvVideoDepacketizer {
// Construct the H264 decode unit // Construct the H264 decode unit
AvDecodeUnit du = new AvDecodeUnit(AvDecodeUnit.TYPE_H264, avcNalDataChain, avcNalDataLength, flags); AvDecodeUnit du = new AvDecodeUnit(AvDecodeUnit.TYPE_H264, avcNalDataChain, avcNalDataLength, flags);
if (!decodedUnits.offer(du)) decodedUnits.offer(du);
{
releaseDecodeUnit(du);
}
// Clear old state // Clear old state
avcNalDataChain = null; avcNalDataChain = null;
@ -134,9 +93,6 @@ public class AvVideoDepacketizer {
{ {
AvByteBufferDescriptor location = packet.getNewPayloadDescriptor(); AvByteBufferDescriptor location = packet.getNewPayloadDescriptor();
// Add an initial reference
packet.addRef();
while (location.length != 0) while (location.length != 0)
{ {
// Remember the start of the NAL data in this packet // Remember the start of the NAL data in this packet
@ -214,20 +170,11 @@ public class AvVideoDepacketizer {
{ {
AvByteBufferDescriptor data = new AvByteBufferDescriptor(location.data, start, location.offset-start); AvByteBufferDescriptor data = new AvByteBufferDescriptor(location.data, start, location.offset-start);
// Attach the current packet as the buffer context and increment the refcount
data.context = packet;
packet.addRef();
// Add a buffer descriptor describing the NAL data in this packet // Add a buffer descriptor describing the NAL data in this packet
avcNalDataChain.add(data); avcNalDataChain.add(data);
avcNalDataLength += location.offset-start; avcNalDataLength += location.offset-start;
} }
} }
// If nothing useful came out of this, release the packet now
if (packet.release() == 0) {
pool.free(location.data);
}
} }
public void addInputData(AvRtpPacket packet) public void addInputData(AvRtpPacket packet)

View File

@ -4,7 +4,6 @@ import com.limelight.nvstream.av.AvByteBufferDescriptor;
public class AvVideoPacket { public class AvVideoPacket {
private AvByteBufferDescriptor buffer; private AvByteBufferDescriptor buffer;
private int refCount;
public AvVideoPacket(AvByteBufferDescriptor rtpPayload) public AvVideoPacket(AvByteBufferDescriptor rtpPayload)
{ {
@ -15,14 +14,4 @@ public class AvVideoPacket {
{ {
return new AvByteBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56); return new AvByteBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56);
} }
public int addRef()
{
return ++refCount;
}
public int release()
{
return --refCount;
}
} }