diff --git a/src/com/limelight/nvstream/NvAudioStream.java b/src/com/limelight/nvstream/NvAudioStream.java index e49202a8..e688b50c 100644 --- a/src/com/limelight/nvstream/NvAudioStream.java +++ b/src/com/limelight/nvstream/NvAudioStream.java @@ -168,7 +168,6 @@ public class NvAudioStream { depacketizer.decodeInputData(packet); pool.free(packet.getBackingBuffer()); - packet.free(); } } }; @@ -210,7 +209,7 @@ public class NvAudioStream { @Override public void run() { DatagramPacket packet = new DatagramPacket(pool.allocate(), 1500); - AvByteBufferDescriptor desc = AvByteBufferDescriptor.newDescriptor(null, 0, 0); + AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0); while (!isInterrupted()) { @@ -226,7 +225,7 @@ public class NvAudioStream { desc.data = packet.getData(); // Give the packet to the depacketizer thread - packets.add(AvRtpPacket.create(desc)); + packets.add(new AvRtpPacket(desc)); // Get a new buffer from the buffer pool packet.setData(pool.allocate(), 0, 1500); diff --git a/src/com/limelight/nvstream/NvVideoStream.java b/src/com/limelight/nvstream/NvVideoStream.java index 44ac2867..e3d903d9 100644 --- a/src/com/limelight/nvstream/NvVideoStream.java +++ b/src/com/limelight/nvstream/NvVideoStream.java @@ -110,7 +110,7 @@ public class NvVideoStream { } System.out.println("VID: First frame read ("+offset+" bytes)"); - depacketizer.addInputData(AvVideoPacket.createNoCopy(AvByteBufferDescriptor.newDescriptor(firstFrame, 0, offset))); + depacketizer.addInputData(new AvVideoPacket(new AvByteBufferDescriptor(firstFrame, 0, offset))); } finally { firstFrameSocket.close(); firstFrameSocket = null; @@ -249,8 +249,6 @@ public class NvVideoStream { // !!! We no longer own the data buffer at this point !!! depacketizer.addInputData(packet); - - packet.free(); } } }; @@ -265,7 +263,7 @@ public class NvVideoStream { @Override public void run() { DatagramPacket packet = new DatagramPacket(depacketizer.allocatePacketBuffer(), 1500); - AvByteBufferDescriptor desc = AvByteBufferDescriptor.newDescriptor(null, 0, 0); + AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0); while (!isInterrupted()) { @@ -281,7 +279,7 @@ public class NvVideoStream { desc.data = packet.getData(); // Give the packet to the depacketizer thread - packets.add(AvRtpPacket.create(desc)); + packets.add(new AvRtpPacket(desc)); // Get a new buffer from the buffer pool packet.setData(depacketizer.allocatePacketBuffer(), 0, 1500); diff --git a/src/com/limelight/nvstream/av/AvByteBufferDescriptor.java b/src/com/limelight/nvstream/av/AvByteBufferDescriptor.java index 7e70c93a..b75a78ef 100644 --- a/src/com/limelight/nvstream/av/AvByteBufferDescriptor.java +++ b/src/com/limelight/nvstream/av/AvByteBufferDescriptor.java @@ -6,42 +6,35 @@ public class AvByteBufferDescriptor { public int length; public Object context; - private static AvObjectPool pool = new AvObjectPool(); - public static AvByteBufferDescriptor newDescriptor(byte[] data, int offset, int length) { - AvByteBufferDescriptor buffer = pool.tryAllocate(); - if (buffer != null) { - buffer.data = data; - buffer.offset = offset; - buffer.length = length; - buffer.context = null; - return buffer; - } - else { - return new AvByteBufferDescriptor(data, offset, length); - } - } - - public static AvByteBufferDescriptor newDescriptor(AvByteBufferDescriptor buffer) { - return newDescriptor(buffer.data, buffer.offset, buffer.length); - } - - private AvByteBufferDescriptor(byte[] data, int offset, int length) + public AvByteBufferDescriptor(byte[] data, int offset, int length) { this.data = data; this.offset = offset; this.length = length; - this.context = null; } - private AvByteBufferDescriptor(AvByteBufferDescriptor desc) + public AvByteBufferDescriptor(AvByteBufferDescriptor desc) { this.data = desc.data; this.offset = desc.offset; this.length = desc.length; - this.context = null; } - public void free() { - pool.free(this); + public void print() + { + print(offset, length); + } + + public void print(int length) + { + print(this.offset, length); + } + + public void print(int offset, int length) + { + for (int i = offset; i < offset+length; i++) { + System.out.printf("%d: %02x \n", i, data[i]); + } + System.out.println(); } } diff --git a/src/com/limelight/nvstream/av/AvByteBufferPool.java b/src/com/limelight/nvstream/av/AvByteBufferPool.java index 1da5e6ad..a4892eaf 100644 --- a/src/com/limelight/nvstream/av/AvByteBufferPool.java +++ b/src/com/limelight/nvstream/av/AvByteBufferPool.java @@ -1,9 +1,9 @@ package com.limelight.nvstream.av; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.LinkedList; public class AvByteBufferPool { - private ConcurrentLinkedQueue bufferList = new ConcurrentLinkedQueue(); + private LinkedList bufferList = new LinkedList(); private int bufferSize; public AvByteBufferPool(int size) @@ -11,22 +11,25 @@ public class AvByteBufferPool { this.bufferSize = size; } - public void purge() + public synchronized void purge() { - bufferList.clear(); + this.bufferList = new LinkedList(); } - public byte[] allocate() + public synchronized byte[] allocate() { - byte[] buff = bufferList.poll(); - if (buff == null) { - buff = new byte[bufferSize]; + if (bufferList.isEmpty()) + { + return new byte[bufferSize]; + } + else + { + return bufferList.removeFirst(); } - return buff; } - public void free(byte[] buffer) + public synchronized void free(byte[] buffer) { - bufferList.add(buffer); + bufferList.addFirst(buffer); } } diff --git a/src/com/limelight/nvstream/av/AvDecodeUnit.java b/src/com/limelight/nvstream/av/AvDecodeUnit.java index 1f4fead9..69300b83 100644 --- a/src/com/limelight/nvstream/av/AvDecodeUnit.java +++ b/src/com/limelight/nvstream/av/AvDecodeUnit.java @@ -12,19 +12,7 @@ public class AvDecodeUnit { private int dataLength; private int flags; - private static AvObjectPool pool = new AvObjectPool(); - public static AvDecodeUnit newDecodeUnit(int type, List bufferList, int dataLength, int flags) { - AvDecodeUnit du = pool.tryAllocate(); - if (du == null) { - du = new AvDecodeUnit(); - } - du.initialize(type, bufferList, dataLength, flags); - return du; - } - - private AvDecodeUnit() { } - - public void initialize(int type, List bufferList, int dataLength, int flags) + public AvDecodeUnit(int type, List bufferList, int dataLength, int flags) { this.type = type; this.bufferList = bufferList; @@ -51,9 +39,4 @@ public class AvDecodeUnit { { return dataLength; } - - public void free() - { - pool.free(this); - } } diff --git a/src/com/limelight/nvstream/av/AvObjectPool.java b/src/com/limelight/nvstream/av/AvObjectPool.java deleted file mode 100644 index 97de612c..00000000 --- a/src/com/limelight/nvstream/av/AvObjectPool.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.limelight.nvstream.av; - -import java.util.concurrent.ConcurrentLinkedQueue; - -public class AvObjectPool { - private ConcurrentLinkedQueue objectList = new ConcurrentLinkedQueue(); - - public void purge() - { - objectList.clear(); - } - - public T tryAllocate() - { - return objectList.poll(); - } - - public void free(T object) - { - objectList.add(object); - } -} diff --git a/src/com/limelight/nvstream/av/AvRtpPacket.java b/src/com/limelight/nvstream/av/AvRtpPacket.java index 50facdb8..8e4250e7 100644 --- a/src/com/limelight/nvstream/av/AvRtpPacket.java +++ b/src/com/limelight/nvstream/av/AvRtpPacket.java @@ -8,26 +8,9 @@ public class AvRtpPacket { private short seqNum; private AvByteBufferDescriptor buffer; - private static AvObjectPool pool = new AvObjectPool(); - - public static AvRtpPacket create(AvByteBufferDescriptor payload) { - return createNoCopy(AvByteBufferDescriptor.newDescriptor(payload)); - } - - public static AvRtpPacket createNoCopy(AvByteBufferDescriptor payload) { - AvRtpPacket pkt = pool.tryAllocate(); - if (pkt == null) { - pkt = new AvRtpPacket(); - } - pkt.initialize(payload); - return pkt; - } - - private AvRtpPacket() { } - - private void initialize(AvByteBufferDescriptor buffer) + public AvRtpPacket(AvByteBufferDescriptor buffer) { - this.buffer = buffer; + this.buffer = new AvByteBufferDescriptor(buffer); ByteBuffer bb = ByteBuffer.wrap(buffer.data, buffer.offset, buffer.length); @@ -56,14 +39,8 @@ public class AvRtpPacket { return buffer.data; } - public void free() - { - buffer.free(); - pool.free(this); - } - public AvByteBufferDescriptor getNewPayloadDescriptor() { - return AvByteBufferDescriptor.newDescriptor(buffer.data, buffer.offset+12, buffer.length-12); + return new AvByteBufferDescriptor(buffer.data, buffer.offset+12, buffer.length-12); } } diff --git a/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java b/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java index 706b5fef..9d028326 100644 --- a/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java +++ b/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java @@ -5,39 +5,17 @@ public class AvShortBufferDescriptor { public int offset; public int length; - private static AvObjectPool pool = new AvObjectPool(); - public static AvShortBufferDescriptor newDescriptor(short[] data, int offset, int length) { - AvShortBufferDescriptor buffer = pool.tryAllocate(); - if (buffer != null) { - buffer.data = data; - buffer.offset = offset; - buffer.length = length; - return buffer; - } - else { - return new AvShortBufferDescriptor(data, offset, length); - } - } - - public static AvShortBufferDescriptor newDescriptor(AvShortBufferDescriptor buffer) { - return newDescriptor(buffer.data, buffer.offset, buffer.length); - } - - private AvShortBufferDescriptor(short[] data, int offset, int length) + public AvShortBufferDescriptor(short[] data, int offset, int length) { this.data = data; this.offset = offset; this.length = length; } - private AvShortBufferDescriptor(AvShortBufferDescriptor desc) + public AvShortBufferDescriptor(AvShortBufferDescriptor desc) { this.data = desc.data; this.offset = desc.offset; this.length = desc.length; } - - public void free() { - pool.free(this); - } } diff --git a/src/com/limelight/nvstream/av/AvShortBufferPool.java b/src/com/limelight/nvstream/av/AvShortBufferPool.java index 012383f8..0b000483 100644 --- a/src/com/limelight/nvstream/av/AvShortBufferPool.java +++ b/src/com/limelight/nvstream/av/AvShortBufferPool.java @@ -1,9 +1,9 @@ package com.limelight.nvstream.av; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.LinkedList; public class AvShortBufferPool { - private ConcurrentLinkedQueue bufferList = new ConcurrentLinkedQueue(); + private LinkedList bufferList = new LinkedList(); private int bufferSize; public AvShortBufferPool(int size) @@ -11,22 +11,25 @@ public class AvShortBufferPool { this.bufferSize = size; } - public void purge() + public synchronized void purge() { - bufferList.clear(); + this.bufferList = new LinkedList(); } - public short[] allocate() + public synchronized short[] allocate() { - short[] buff = bufferList.poll(); - if (buff == null) { - buff = new short[bufferSize]; + if (bufferList.isEmpty()) + { + return new short[bufferSize]; + } + else + { + return bufferList.removeFirst(); } - return buff; } - public void free(short[] buffer) + public synchronized void free(short[] buffer) { - bufferList.add(buffer); + bufferList.addFirst(buffer); } } diff --git a/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java b/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java index 32dca37c..13a78f4b 100644 --- a/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java +++ b/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java @@ -32,13 +32,13 @@ public class AvAudioDepacketizer { decodeLen *= OpusDecoder.getChannelCount(); // Put it on the decoded queue - AvShortBufferDescriptor sbd = AvShortBufferDescriptor.newDescriptor(pcmData, 0, decodeLen); - if (!decodedUnits.offer(sbd)) + if (!decodedUnits.offer(new AvShortBufferDescriptor(pcmData, 0, decodeLen))) { - releaseBuffer(sbd); + pool.free(pcmData); } } else { + System.out.println("decode failed: "+decodeLen); pool.free(pcmData); } } @@ -66,13 +66,11 @@ public class AvAudioDepacketizer { // This is all the depacketizing we need to do AvByteBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor(); decodeData(rtpPayload.data, rtpPayload.offset, rtpPayload.length); - rtpPayload.free(); } public void releaseBuffer(AvShortBufferDescriptor decodedData) { pool.free(decodedData.data); - decodedData.free(); } public AvShortBufferDescriptor getNextDecodedData() throws InterruptedException diff --git a/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java b/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java index 646b0b7d..db1d6b01 100644 --- a/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java +++ b/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java @@ -13,7 +13,7 @@ import android.media.MediaCodec; public class AvVideoDepacketizer { // Current NAL state - private LinkedList avcNalDataChain = new LinkedList(); + private LinkedList avcNalDataChain = null; private int avcNalDataLength = 0; private int currentlyDecoding; @@ -22,33 +22,33 @@ public class AvVideoDepacketizer { private LinkedBlockingQueue decodedUnits = new LinkedBlockingQueue(); - private AvByteBufferPool bbPool = new AvByteBufferPool(1500); + private AvByteBufferPool pool = new AvByteBufferPool(1500); public byte[] allocatePacketBuffer() { - return bbPool.allocate(); + return pool.allocate(); } public void trim() { - bbPool.purge(); + pool.purge(); } private void clearAvcNalState() { - for (AvByteBufferDescriptor avbb : avcNalDataChain) + if (avcNalDataChain != null) { - AvVideoPacket packet = (AvVideoPacket) avbb.context; - - if (packet.release() == 0) { - bbPool.free(avbb.data); - packet.free(); + for (AvByteBufferDescriptor avbb : avcNalDataChain) + { + AvVideoPacket packet = (AvVideoPacket) avbb.context; + + if (packet.release() == 0) { + pool.free(avbb.data); + } } - - avbb.free(); } - avcNalDataChain.clear(); + avcNalDataChain = null; avcNalDataLength = 0; } @@ -60,20 +60,15 @@ public class AvVideoDepacketizer { AvVideoPacket packet = (AvVideoPacket) buff.context; if (packet.release() == 0) { - bbPool.free(buff.data); - packet.free(); + pool.free(buff.data); } - - buff.free(); } - - decodeUnit.free(); } private void reassembleAvcNal() { // This is the start of a new NAL - if (!avcNalDataChain.isEmpty() && avcNalDataLength != 0) + if (avcNalDataChain != null && avcNalDataLength != 0) { int flags = 0; @@ -113,8 +108,6 @@ public class AvVideoDepacketizer { header.data[header.offset+4]); break; } - - specialSeq.free(); } else { @@ -125,14 +118,14 @@ public class AvVideoDepacketizer { } // Construct the H264 decode unit - AvDecodeUnit du = AvDecodeUnit.newDecodeUnit(AvDecodeUnit.TYPE_H264, avcNalDataChain, avcNalDataLength, flags); + AvDecodeUnit du = new AvDecodeUnit(AvDecodeUnit.TYPE_H264, avcNalDataChain, avcNalDataLength, flags); if (!decodedUnits.offer(du)) { releaseDecodeUnit(du); } // Clear old state - avcNalDataChain.clear(); + avcNalDataChain = null; avcNalDataLength = 0; } } @@ -165,7 +158,7 @@ public class AvVideoDepacketizer { reassembleAvcNal(); // Setup state for the new NAL - avcNalDataChain.clear(); + avcNalDataChain = new LinkedList(); avcNalDataLength = 0; } @@ -217,10 +210,9 @@ public class AvVideoDepacketizer { location.length--; } - if (currentlyDecoding == AvDecodeUnit.TYPE_H264) + if (currentlyDecoding == AvDecodeUnit.TYPE_H264 && avcNalDataChain != null) { - // This is release if the NAL is cleared or decoded - AvByteBufferDescriptor data = AvByteBufferDescriptor.newDescriptor(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; @@ -234,12 +226,8 @@ public class AvVideoDepacketizer { // If nothing useful came out of this, release the packet now if (packet.release() == 0) { - bbPool.free(location.data); - packet.free(); + pool.free(location.data); } - - // Done with the buffer descriptor - location.free(); } public void addInputData(AvRtpPacket packet) @@ -260,9 +248,9 @@ public class AvVideoDepacketizer { lastSequenceNumber = seq; - // Pass the payload to the non-sequencing parser. It now owns that descriptor. + // Pass the payload to the non-sequencing parser AvByteBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor(); - addInputData(AvVideoPacket.createNoCopy(rtpPayload)); + addInputData(new AvVideoPacket(rtpPayload)); } public AvDecodeUnit getNextDecodeUnit() throws InterruptedException @@ -316,19 +304,19 @@ class NAL { buffer.data[buffer.offset+3] == 0x01) { // It's the AVC start sequence 00 00 00 01 - return AvByteBufferDescriptor.newDescriptor(buffer.data, buffer.offset, 4); + return new AvByteBufferDescriptor(buffer.data, buffer.offset, 4); } else { // It's 00 00 00 - return AvByteBufferDescriptor.newDescriptor(buffer.data, buffer.offset, 3); + return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3); } } else if (buffer.data[buffer.offset+2] == 0x01 || buffer.data[buffer.offset+2] == 0x02) { // These are easy: 00 00 01 or 00 00 02 - return AvByteBufferDescriptor.newDescriptor(buffer.data, buffer.offset, 3); + return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3); } else if (buffer.data[buffer.offset+2] == 0x03) { @@ -350,7 +338,7 @@ class NAL { else { // It's not a standard replacement so it's a special sequence - return AvByteBufferDescriptor.newDescriptor(buffer.data, buffer.offset, 3); + return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3); } } } diff --git a/src/com/limelight/nvstream/av/video/AvVideoPacket.java b/src/com/limelight/nvstream/av/video/AvVideoPacket.java index 3aa751a9..fde7bc54 100644 --- a/src/com/limelight/nvstream/av/video/AvVideoPacket.java +++ b/src/com/limelight/nvstream/av/video/AvVideoPacket.java @@ -1,34 +1,19 @@ package com.limelight.nvstream.av.video; import com.limelight.nvstream.av.AvByteBufferDescriptor; -import com.limelight.nvstream.av.AvObjectPool; public class AvVideoPacket { private AvByteBufferDescriptor buffer; private int refCount; - private static AvObjectPool pool = new AvObjectPool(); - - public static AvVideoPacket createNoCopy(AvByteBufferDescriptor payload) { - AvVideoPacket pkt = pool.tryAllocate(); - if (pkt != null) { - pkt.buffer = payload; - pkt.refCount = 0; - return pkt; - } - else { - return new AvVideoPacket(payload); - } - } - - private AvVideoPacket(AvByteBufferDescriptor rtpPayload) + public AvVideoPacket(AvByteBufferDescriptor rtpPayload) { - buffer = rtpPayload; + buffer = new AvByteBufferDescriptor(rtpPayload); } public AvByteBufferDescriptor getNewPayloadDescriptor() { - return AvByteBufferDescriptor.newDescriptor(buffer.data, buffer.offset+56, buffer.length-56); + return new AvByteBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56); } public int addRef() @@ -40,10 +25,4 @@ public class AvVideoPacket { { return --refCount; } - - public void free() - { - buffer.free(); - pool.free(this); - } }