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:
Cameron Gutman
2013-11-23 02:44:10 -05:00
parent 4d5849f448
commit 125bcb370f
6 changed files with 66 additions and 26 deletions

View File

@@ -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"

View File

@@ -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);
}
}
}
};

View File

@@ -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);
}
}
}
};

View File

@@ -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();
}
}
}

View File

@@ -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;

View File

@@ -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);