mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-02-16 10:31:07 +00:00
Limit the size of queues. Switch to a blacklist instead of a whitelist for hardware decoding. Currently, Nvidia, TI, and Google H264 codecs are on the blacklist. Reenable large heap since we're allocating more objects now.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:largeHeap="true"
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
|
||||
import com.limelight.nvstream.av.AvByteBufferDescriptor;
|
||||
import com.limelight.nvstream.av.AvRtpPacket;
|
||||
@@ -22,7 +22,7 @@ public class NvAudioStream {
|
||||
public static final int RTP_PORT = 48000;
|
||||
public static final int RTCP_PORT = 47999;
|
||||
|
||||
private LinkedBlockingQueue<AvRtpPacket> packets = new LinkedBlockingQueue<AvRtpPacket>();
|
||||
private ArrayBlockingQueue<AvRtpPacket> packets = new ArrayBlockingQueue<AvRtpPacket>(100);
|
||||
|
||||
private AudioTrack track;
|
||||
|
||||
@@ -201,10 +201,10 @@ public class NvAudioStream {
|
||||
desc.data = packet.getData();
|
||||
|
||||
// Give the packet to the depacketizer thread
|
||||
packets.add(new AvRtpPacket(desc));
|
||||
|
||||
// Get a new buffer from the buffer pool
|
||||
packet.setData(new byte[1500], 0, 1500);
|
||||
if (packets.offer(new AvRtpPacket(desc))) {
|
||||
// Get a new buffer from the buffer pool
|
||||
packet.setData(new byte[1500], 0, 1500);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
|
||||
import com.limelight.nvstream.av.AvByteBufferDescriptor;
|
||||
import com.limelight.nvstream.av.AvDecodeUnit;
|
||||
@@ -31,7 +31,7 @@ public class NvVideoStream {
|
||||
|
||||
public static final int FIRST_FRAME_TIMEOUT = 3000;
|
||||
|
||||
private LinkedBlockingQueue<AvRtpPacket> packets = new LinkedBlockingQueue<AvRtpPacket>();
|
||||
private ArrayBlockingQueue<AvRtpPacket> packets = new ArrayBlockingQueue<AvRtpPacket>(100);
|
||||
|
||||
private InetAddress host;
|
||||
private DatagramSocket rtp;
|
||||
@@ -135,7 +135,7 @@ public class NvVideoStream {
|
||||
// Emulator - don't render video (it's slow!)
|
||||
decrend = null;
|
||||
}
|
||||
else if (MediaCodecDecoderRenderer.hasWhitelistedDecoder()) {
|
||||
else if (MediaCodecDecoderRenderer.findSafeDecoder() != null) {
|
||||
// Hardware decoding
|
||||
decrend = new MediaCodecDecoderRenderer();
|
||||
}
|
||||
@@ -260,10 +260,10 @@ public class NvVideoStream {
|
||||
desc.data = packet.getData();
|
||||
|
||||
// Give the packet to the depacketizer thread
|
||||
packets.add(new AvRtpPacket(desc));
|
||||
|
||||
// Get a new buffer from the buffer pool
|
||||
packet.setData(new byte[1500], 0, 1500);
|
||||
if (packets.offer(new AvRtpPacket(desc))) {
|
||||
// Get a new buffer from the buffer pool
|
||||
packet.setData(new byte[1500], 0, 1500);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package com.limelight.nvstream.av.audio;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
|
||||
import com.limelight.nvstream.av.AvByteBufferDescriptor;
|
||||
import com.limelight.nvstream.av.AvRtpPacket;
|
||||
import com.limelight.nvstream.av.AvShortBufferDescriptor;
|
||||
|
||||
public class AvAudioDepacketizer {
|
||||
private LinkedBlockingQueue<AvShortBufferDescriptor> decodedUnits =
|
||||
new LinkedBlockingQueue<AvShortBufferDescriptor>(15);
|
||||
private ArrayBlockingQueue<AvShortBufferDescriptor> decodedUnits =
|
||||
new ArrayBlockingQueue<AvShortBufferDescriptor>(15);
|
||||
|
||||
// Sequencing state
|
||||
private short lastSequenceNumber;
|
||||
@@ -24,7 +24,10 @@ public class AvAudioDepacketizer {
|
||||
decodeLen *= OpusDecoder.getChannelCount();
|
||||
|
||||
// Put it on the decoded queue
|
||||
decodedUnits.offer(new AvShortBufferDescriptor(pcmData, 0, decodeLen));
|
||||
if (!decodedUnits.offer(new AvShortBufferDescriptor(pcmData, 0, decodeLen))) {
|
||||
// Clear out the queue
|
||||
decodedUnits.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.limelight.nvstream.av.video;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
|
||||
import com.limelight.nvstream.av.AvByteBufferDescriptor;
|
||||
import com.limelight.nvstream.av.AvDecodeUnit;
|
||||
@@ -22,7 +22,8 @@ public class AvVideoDepacketizer {
|
||||
|
||||
private ConnectionStatusListener controlListener;
|
||||
|
||||
private LinkedBlockingQueue<AvDecodeUnit> decodedUnits = new LinkedBlockingQueue<AvDecodeUnit>();
|
||||
private static final int DU_LIMIT = 30;
|
||||
private ArrayBlockingQueue<AvDecodeUnit> decodedUnits = new ArrayBlockingQueue<AvDecodeUnit>(DU_LIMIT);
|
||||
|
||||
public AvVideoDepacketizer(ConnectionStatusListener controlListener)
|
||||
{
|
||||
@@ -89,7 +90,11 @@ public class AvVideoDepacketizer {
|
||||
|
||||
// Construct the H264 decode unit
|
||||
AvDecodeUnit du = new AvDecodeUnit(AvDecodeUnit.TYPE_H264, avcNalDataChain, avcNalDataLength, flags);
|
||||
decodedUnits.offer(du);
|
||||
if (!decodedUnits.offer(du)) {
|
||||
// We need a new IDR frame since we're discarding data now
|
||||
decodedUnits.clear();
|
||||
controlListener.connectionNeedsResync();
|
||||
}
|
||||
|
||||
// Clear old state
|
||||
avcNalDataChain = null;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.limelight.nvstream.av.video;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.limelight.nvstream.av.AvByteBufferDescriptor;
|
||||
import com.limelight.nvstream.av.AvDecodeUnit;
|
||||
@@ -20,28 +22,57 @@ public class MediaCodecDecoderRenderer implements DecoderRenderer {
|
||||
private ByteBuffer[] videoDecoderInputBuffers;
|
||||
private MediaCodec videoDecoder;
|
||||
private Thread rendererThread;
|
||||
|
||||
public static final List<String> blacklistedDecoderPrefixes;
|
||||
|
||||
static {
|
||||
blacklistedDecoderPrefixes = new LinkedList<String>();
|
||||
blacklistedDecoderPrefixes.add("omx.google");
|
||||
blacklistedDecoderPrefixes.add("omx.nvidia");
|
||||
blacklistedDecoderPrefixes.add("omx.TI");
|
||||
}
|
||||
|
||||
public static MediaCodecInfo findSafeDecoder() {
|
||||
|
||||
public static boolean hasWhitelistedDecoder() {
|
||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
||||
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
||||
boolean badCodec = false;
|
||||
|
||||
// Skip encoders
|
||||
if (codecInfo.isEncoder()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (codecInfo.getName().equalsIgnoreCase("omx.qcom.video.decoder.avc") ||
|
||||
codecInfo.getName().equalsIgnoreCase("OMX.Exynos.AVC.Decoder")) {
|
||||
return true;
|
||||
for (String badPrefix : blacklistedDecoderPrefixes) {
|
||||
String name = codecInfo.getName();
|
||||
if (name.length() > badPrefix.length()) {
|
||||
String prefix = name.substring(0, badPrefix.length());
|
||||
if (prefix.equalsIgnoreCase(badPrefix)) {
|
||||
badCodec = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (badCodec) {
|
||||
System.out.println("Blacklisted decoder: "+codecInfo.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String mime : codecInfo.getSupportedTypes()) {
|
||||
if (mime.equalsIgnoreCase("video/avc")) {
|
||||
System.out.println("Selected decoder: "+codecInfo.getName());
|
||||
return codecInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(int width, int height, Surface renderTarget) {
|
||||
videoDecoder = MediaCodec.createDecoderByType("video/avc");
|
||||
videoDecoder = MediaCodec.createByCodecName(findSafeDecoder().getName());
|
||||
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
|
||||
|
||||
videoDecoder.configure(videoFormat, renderTarget, null, 0);
|
||||
|
||||
Reference in New Issue
Block a user