mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-20 11:33:06 +00:00
Use a packet buffer pool to reduce memory pressure
This commit is contained in:
parent
e6af9df142
commit
e5126ebe01
@ -16,6 +16,7 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
import com.limelight.nvstream.av.AvBufferDescriptor;
|
import com.limelight.nvstream.av.AvBufferDescriptor;
|
||||||
|
import com.limelight.nvstream.av.AvBufferPool;
|
||||||
import com.limelight.nvstream.av.AvDecodeUnit;
|
import com.limelight.nvstream.av.AvDecodeUnit;
|
||||||
import com.limelight.nvstream.av.AvPacket;
|
import com.limelight.nvstream.av.AvPacket;
|
||||||
import com.limelight.nvstream.av.AvParser;
|
import com.limelight.nvstream.av.AvParser;
|
||||||
@ -35,10 +36,11 @@ public class NvVideoStream {
|
|||||||
public static final int RTCP_PORT = 47999;
|
public static final int RTCP_PORT = 47999;
|
||||||
public static final int FIRST_FRAME_PORT = 47996;
|
public static final int FIRST_FRAME_PORT = 47996;
|
||||||
|
|
||||||
private static final int FRAME_RATE = 60;
|
|
||||||
private ByteBuffer[] videoDecoderInputBuffers = null;
|
private ByteBuffer[] videoDecoderInputBuffers = null;
|
||||||
private MediaCodec videoDecoder;
|
private MediaCodec videoDecoder;
|
||||||
|
|
||||||
|
private AvBufferPool pool = new AvBufferPool(1500);
|
||||||
|
|
||||||
private AvParser parser = new AvParser();
|
private AvParser parser = new AvParser();
|
||||||
|
|
||||||
private InputStream getFirstFrame(String host) throws UnknownHostException, IOException
|
private InputStream getFirstFrame(String host) throws UnknownHostException, IOException
|
||||||
@ -151,6 +153,9 @@ public class NvVideoStream {
|
|||||||
for (AvBufferDescriptor desc : du.getBufferList())
|
for (AvBufferDescriptor desc : du.getBufferList())
|
||||||
{
|
{
|
||||||
buf.put(desc.data, desc.offset, desc.length);
|
buf.put(desc.data, desc.offset, desc.length);
|
||||||
|
|
||||||
|
// Release the buffer back to the buffer pool
|
||||||
|
pool.free(desc.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
videoDecoder.queueInputBuffer(inputIndex,
|
videoDecoder.queueInputBuffer(inputIndex,
|
||||||
@ -175,13 +180,11 @@ public class NvVideoStream {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
byte[] buffer = new byte[1500];
|
DatagramPacket packet = new DatagramPacket(pool.allocate(), 1500);
|
||||||
AvBufferDescriptor desc = new AvBufferDescriptor(null, 0, 0);
|
AvBufferDescriptor desc = new AvBufferDescriptor(null, 0, 0);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
rtp.receive(packet);
|
rtp.receive(packet);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -198,12 +201,13 @@ public class NvVideoStream {
|
|||||||
desc.offset += 12;
|
desc.offset += 12;
|
||||||
desc.length -= 12;
|
desc.length -= 12;
|
||||||
|
|
||||||
// Give the data to the AV parser
|
// !!! We no longer own the data buffer at this point !!!
|
||||||
parser.addInputData(new AvPacket(desc));
|
parser.addInputData(new AvPacket(desc));
|
||||||
|
|
||||||
|
// Get a new buffer from the buffer pool
|
||||||
|
packet.setData(pool.allocate(), 0, 1500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -232,11 +236,4 @@ public class NvVideoStream {
|
|||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the presentation time for frame N, in microseconds.
|
|
||||||
*/
|
|
||||||
private static long computePresentationTime(int frameIndex) {
|
|
||||||
return 132 + frameIndex * 1000000 / FRAME_RATE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
30
src/com/limelight/nvstream/av/AvBufferPool.java
Normal file
30
src/com/limelight/nvstream/av/AvBufferPool.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package com.limelight.nvstream.av;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class AvBufferPool {
|
||||||
|
private LinkedList<byte[]> bufferList = new LinkedList<byte[]>();
|
||||||
|
private int bufferSize;
|
||||||
|
|
||||||
|
public AvBufferPool(int size)
|
||||||
|
{
|
||||||
|
this.bufferSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized byte[] allocate()
|
||||||
|
{
|
||||||
|
if (bufferList.isEmpty())
|
||||||
|
{
|
||||||
|
return new byte[bufferSize];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return bufferList.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void free(byte[] buffer)
|
||||||
|
{
|
||||||
|
bufferList.addFirst(buffer);
|
||||||
|
}
|
||||||
|
}
|
@ -5,14 +5,11 @@ public class AvPacket {
|
|||||||
|
|
||||||
public AvPacket(AvBufferDescriptor rtpPayload)
|
public AvPacket(AvBufferDescriptor rtpPayload)
|
||||||
{
|
{
|
||||||
byte[] data = new byte[rtpPayload.length];
|
buffer = new AvBufferDescriptor(rtpPayload.data, rtpPayload.offset, rtpPayload.length);
|
||||||
System.arraycopy(rtpPayload.data, rtpPayload.offset, data, 0, rtpPayload.length);
|
|
||||||
buffer = new AvBufferDescriptor(data, 0, data.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AvBufferDescriptor getPayload()
|
public AvBufferDescriptor getNewPayloadDescriptor()
|
||||||
{
|
{
|
||||||
int payloadOffset = buffer.offset+56;
|
return new AvBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56);
|
||||||
return new AvBufferDescriptor(buffer.data, payloadOffset, buffer.length-payloadOffset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.limelight.nvstream.av;
|
package com.limelight.nvstream.av;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
public class AvParser {
|
public class AvParser {
|
||||||
@ -29,8 +28,9 @@ public class AvParser {
|
|||||||
|
|
||||||
public void addInputData(AvPacket packet)
|
public void addInputData(AvPacket packet)
|
||||||
{
|
{
|
||||||
AvBufferDescriptor payload = packet.getPayload();
|
// This payload buffer descriptor belongs to us
|
||||||
AvBufferDescriptor location = new AvBufferDescriptor(payload.data, payload.offset, payload.length);
|
AvBufferDescriptor location = packet.getNewPayloadDescriptor();
|
||||||
|
int payloadLength = location.length;
|
||||||
|
|
||||||
while (location.length != 0)
|
while (location.length != 0)
|
||||||
{
|
{
|
||||||
@ -47,9 +47,9 @@ public class AvParser {
|
|||||||
nalDataChain = new LinkedList<AvBufferDescriptor>();
|
nalDataChain = new LinkedList<AvBufferDescriptor>();
|
||||||
nalDataLength = 0;
|
nalDataLength = 0;
|
||||||
|
|
||||||
// Skip the start sequence and the type byte
|
// Skip the start sequence
|
||||||
location.length -= 5;
|
location.length -= 4;
|
||||||
location.offset += 5;
|
location.offset += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's a NAL assembly in progress, add the current data
|
// If there's a NAL assembly in progress, add the current data
|
||||||
@ -58,7 +58,7 @@ public class AvParser {
|
|||||||
// FIXME: This is a hack to make parsing full packets
|
// FIXME: This is a hack to make parsing full packets
|
||||||
// take less time. We assume if they don't start with
|
// take less time. We assume if they don't start with
|
||||||
// a NAL start sequence, they're full of NAL data
|
// a NAL start sequence, they're full of NAL data
|
||||||
if (payload.length == 968)
|
if (payloadLength == 968)
|
||||||
{
|
{
|
||||||
location.offset += location.length;
|
location.offset += location.length;
|
||||||
location.length = 0;
|
location.length = 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user