mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-06-17 06:10:58 +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" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:largeHeap="true"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import java.net.DatagramSocket;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.LinkedList;
|
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.AvByteBufferDescriptor;
|
||||||
import com.limelight.nvstream.av.AvRtpPacket;
|
import com.limelight.nvstream.av.AvRtpPacket;
|
||||||
@@ -22,7 +22,7 @@ public class NvAudioStream {
|
|||||||
public static final int RTP_PORT = 48000;
|
public static final int RTP_PORT = 48000;
|
||||||
public static final int RTCP_PORT = 47999;
|
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;
|
private AudioTrack track;
|
||||||
|
|
||||||
@@ -201,10 +201,10 @@ public class NvAudioStream {
|
|||||||
desc.data = packet.getData();
|
desc.data = packet.getData();
|
||||||
|
|
||||||
// Give the packet to the depacketizer thread
|
// Give the packet to the depacketizer thread
|
||||||
packets.add(new AvRtpPacket(desc));
|
if (packets.offer(new AvRtpPacket(desc))) {
|
||||||
|
// Get a new buffer from the buffer pool
|
||||||
// Get a new buffer from the buffer pool
|
packet.setData(new byte[1500], 0, 1500);
|
||||||
packet.setData(new byte[1500], 0, 1500);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.LinkedList;
|
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.AvByteBufferDescriptor;
|
||||||
import com.limelight.nvstream.av.AvDecodeUnit;
|
import com.limelight.nvstream.av.AvDecodeUnit;
|
||||||
@@ -31,7 +31,7 @@ public class NvVideoStream {
|
|||||||
|
|
||||||
public static final int FIRST_FRAME_TIMEOUT = 3000;
|
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 InetAddress host;
|
||||||
private DatagramSocket rtp;
|
private DatagramSocket rtp;
|
||||||
@@ -135,7 +135,7 @@ public class NvVideoStream {
|
|||||||
// Emulator - don't render video (it's slow!)
|
// Emulator - don't render video (it's slow!)
|
||||||
decrend = null;
|
decrend = null;
|
||||||
}
|
}
|
||||||
else if (MediaCodecDecoderRenderer.hasWhitelistedDecoder()) {
|
else if (MediaCodecDecoderRenderer.findSafeDecoder() != null) {
|
||||||
// Hardware decoding
|
// Hardware decoding
|
||||||
decrend = new MediaCodecDecoderRenderer();
|
decrend = new MediaCodecDecoderRenderer();
|
||||||
}
|
}
|
||||||
@@ -260,10 +260,10 @@ public class NvVideoStream {
|
|||||||
desc.data = packet.getData();
|
desc.data = packet.getData();
|
||||||
|
|
||||||
// Give the packet to the depacketizer thread
|
// Give the packet to the depacketizer thread
|
||||||
packets.add(new AvRtpPacket(desc));
|
if (packets.offer(new AvRtpPacket(desc))) {
|
||||||
|
// Get a new buffer from the buffer pool
|
||||||
// Get a new buffer from the buffer pool
|
packet.setData(new byte[1500], 0, 1500);
|
||||||
packet.setData(new byte[1500], 0, 1500);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.limelight.nvstream.av.audio;
|
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.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;
|
||||||
|
|
||||||
public class AvAudioDepacketizer {
|
public class AvAudioDepacketizer {
|
||||||
private LinkedBlockingQueue<AvShortBufferDescriptor> decodedUnits =
|
private ArrayBlockingQueue<AvShortBufferDescriptor> decodedUnits =
|
||||||
new LinkedBlockingQueue<AvShortBufferDescriptor>(15);
|
new ArrayBlockingQueue<AvShortBufferDescriptor>(15);
|
||||||
|
|
||||||
// Sequencing state
|
// Sequencing state
|
||||||
private short lastSequenceNumber;
|
private short lastSequenceNumber;
|
||||||
@@ -24,7 +24,10 @@ public class AvAudioDepacketizer {
|
|||||||
decodeLen *= OpusDecoder.getChannelCount();
|
decodeLen *= OpusDecoder.getChannelCount();
|
||||||
|
|
||||||
// Put it on the decoded queue
|
// 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;
|
package com.limelight.nvstream.av.video;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
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.AvByteBufferDescriptor;
|
||||||
import com.limelight.nvstream.av.AvDecodeUnit;
|
import com.limelight.nvstream.av.AvDecodeUnit;
|
||||||
@@ -22,7 +22,8 @@ public class AvVideoDepacketizer {
|
|||||||
|
|
||||||
private ConnectionStatusListener controlListener;
|
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)
|
public AvVideoDepacketizer(ConnectionStatusListener controlListener)
|
||||||
{
|
{
|
||||||
@@ -89,7 +90,11 @@ 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);
|
||||||
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
|
// Clear old state
|
||||||
avcNalDataChain = null;
|
avcNalDataChain = null;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.limelight.nvstream.av.video;
|
package com.limelight.nvstream.av.video;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.limelight.nvstream.av.AvByteBufferDescriptor;
|
import com.limelight.nvstream.av.AvByteBufferDescriptor;
|
||||||
import com.limelight.nvstream.av.AvDecodeUnit;
|
import com.limelight.nvstream.av.AvDecodeUnit;
|
||||||
@@ -21,27 +23,56 @@ public class MediaCodecDecoderRenderer implements DecoderRenderer {
|
|||||||
private MediaCodec videoDecoder;
|
private MediaCodec videoDecoder;
|
||||||
private Thread rendererThread;
|
private Thread rendererThread;
|
||||||
|
|
||||||
public static boolean hasWhitelistedDecoder() {
|
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() {
|
||||||
|
|
||||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
||||||
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
||||||
|
boolean badCodec = false;
|
||||||
|
|
||||||
// Skip encoders
|
// Skip encoders
|
||||||
if (codecInfo.isEncoder()) {
|
if (codecInfo.isEncoder()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codecInfo.getName().equalsIgnoreCase("omx.qcom.video.decoder.avc") ||
|
for (String badPrefix : blacklistedDecoderPrefixes) {
|
||||||
codecInfo.getName().equalsIgnoreCase("OMX.Exynos.AVC.Decoder")) {
|
String name = codecInfo.getName();
|
||||||
return true;
|
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
|
@Override
|
||||||
public void setup(int width, int height, Surface renderTarget) {
|
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);
|
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
|
||||||
|
|
||||||
videoDecoder.configure(videoFormat, renderTarget, null, 0);
|
videoDecoder.configure(videoFormat, renderTarget, null, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user