Merge branch 'master' into root

Conflicts:
	AndroidManifest.xml
	src/com/limelight/binding/input/evdev/EvdevWatcher.java
This commit is contained in:
Cameron Gutman 2014-09-20 02:54:15 -07:00
commit 1b026f1354
7 changed files with 148 additions and 156 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.limelight.root" package="com.limelight.root"
android:versionCode="33" android:versionCode="34"
android:versionName="2.5.4.1" > android:versionName="2.5.5" >
<uses-sdk <uses-sdk
android:minSdkVersion="16" android:minSdkVersion="16"

BIN
libs/jcodec-0.1.5.jar Normal file

Binary file not shown.

Binary file not shown.

View File

@ -190,16 +190,20 @@ public class Game extends Activity implements SurfaceHolder.Callback,
String host = Game.this.getIntent().getStringExtra(EXTRA_HOST); String host = Game.this.getIntent().getStringExtra(EXTRA_HOST);
String app = Game.this.getIntent().getStringExtra(EXTRA_APP); String app = Game.this.getIntent().getStringExtra(EXTRA_APP);
String uniqueId = Game.this.getIntent().getStringExtra(EXTRA_UNIQUEID); String uniqueId = Game.this.getIntent().getStringExtra(EXTRA_UNIQUEID);
// Initialize the connection
conn = new NvConnection(host, uniqueId, Game.this,
new StreamConfiguration(app, width, height, refreshRate, bitrate * 1000, sops),
PlatformBinding.getCryptoProvider(this));
keybTranslator = new KeyboardTranslator(conn);
controllerHandler = new ControllerHandler(conn);
decoderRenderer = new ConfigurableDecoderRenderer(); decoderRenderer = new ConfigurableDecoderRenderer();
decoderRenderer.initializeWithFlags(drFlags); decoderRenderer.initializeWithFlags(drFlags);
StreamConfiguration config =
new StreamConfiguration(app, width, height,
refreshRate, bitrate * 1000, sops,
(decoderRenderer.getCapabilities() &
VideoDecoderRenderer.CAPABILITY_ADAPTIVE_RESOLUTION) != 0);
// Initialize the connection
conn = new NvConnection(host, uniqueId, Game.this, config, PlatformBinding.getCryptoProvider(this));
keybTranslator = new KeyboardTranslator(conn);
controllerHandler = new ControllerHandler(conn);
SurfaceHolder sh = sv.getHolder(); SurfaceHolder sh = sv.getHolder();
if (stretchToFit || !decoderRenderer.isHardwareAccelerated()) { if (stretchToFit || !decoderRenderer.isHardwareAccelerated()) {

View File

@ -157,7 +157,7 @@ public class PcView extends Activity {
} }
} }
private void stopComputerUpdates() { private void stopComputerUpdates(boolean wait) {
if (managerBinder != null) { if (managerBinder != null) {
if (!runningPolling) { if (!runningPolling) {
return; return;
@ -166,6 +166,11 @@ public class PcView extends Activity {
freezeUpdates = true; freezeUpdates = true;
managerBinder.stopPolling(); managerBinder.stopPolling();
if (wait) {
managerBinder.waitForPollingStopped();
}
runningPolling = false; runningPolling = false;
} }
} }
@ -190,7 +195,7 @@ public class PcView extends Activity {
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
stopComputerUpdates(); stopComputerUpdates(false);
} }
@Override @Override
@ -202,7 +207,7 @@ public class PcView extends Activity {
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
stopComputerUpdates(); stopComputerUpdates(false);
// Call superclass // Call superclass
super.onCreateContextMenu(menu, v, menuInfo); super.onCreateContextMenu(menu, v, menuInfo);
@ -259,6 +264,9 @@ public class PcView extends Activity {
NvHTTP httpConn; NvHTTP httpConn;
String message; String message;
try { try {
// Stop updates and wait while pairing
stopComputerUpdates(true);
InetAddress addr = null; InetAddress addr = null;
if (computer.reachability == ComputerDetails.Reachability.LOCAL) { if (computer.reachability == ComputerDetails.Reachability.LOCAL) {
addr = computer.localIp; addr = computer.localIp;
@ -313,6 +321,9 @@ public class PcView extends Activity {
Toast.makeText(PcView.this, toastMessage, Toast.LENGTH_LONG).show(); Toast.makeText(PcView.this, toastMessage, Toast.LENGTH_LONG).show();
} }
}); });
// Start polling again
startComputerUpdates();
} }
}).start(); }).start();
} }

View File

@ -5,12 +5,16 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.LockSupport;
import org.jcodec.codecs.h264.io.model.SeqParameterSet;
import org.jcodec.codecs.h264.io.model.VUIParameters;
import com.limelight.LimeLog; import com.limelight.LimeLog;
import com.limelight.nvstream.av.ByteBufferDescriptor; import com.limelight.nvstream.av.ByteBufferDescriptor;
import com.limelight.nvstream.av.DecodeUnit; import com.limelight.nvstream.av.DecodeUnit;
import com.limelight.nvstream.av.video.VideoDecoderRenderer; import com.limelight.nvstream.av.video.VideoDecoderRenderer;
import com.limelight.nvstream.av.video.VideoDepacketizer; import com.limelight.nvstream.av.video.VideoDepacketizer;
import android.annotation.TargetApi;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecCapabilities; import android.media.MediaCodecInfo.CodecCapabilities;
@ -18,6 +22,7 @@ import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaCodecList; import android.media.MediaCodecList;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.media.MediaCodec.BufferInfo; import android.media.MediaCodec.BufferInfo;
import android.os.Build;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
public class MediaCodecDecoderRenderer implements VideoDecoderRenderer { public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
@ -28,6 +33,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
private boolean needsSpsBitstreamFixup; private boolean needsSpsBitstreamFixup;
private boolean needsSpsNumRefFixup; private boolean needsSpsNumRefFixup;
private VideoDepacketizer depacketizer; private VideoDepacketizer depacketizer;
private boolean adaptivePlayback;
private long totalTimeMs; private long totalTimeMs;
private long decoderTimeMs; private long decoderTimeMs;
@ -38,11 +44,10 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
private int numPpsIn; private int numPpsIn;
private int numIframeIn; private int numIframeIn;
private final static byte[] BITSTREAM_RESTRICTIONS = new byte[] {(byte) 0xF1, (byte) 0x83, 0x2A, 0x00};
public static final List<String> blacklistedDecoderPrefixes; public static final List<String> blacklistedDecoderPrefixes;
public static final List<String> spsFixupBitstreamFixupDecoderPrefixes; public static final List<String> spsFixupBitstreamFixupDecoderPrefixes;
public static final List<String> spsFixupNumRefFixupDecoderPrefixes; public static final List<String> spsFixupNumRefFixupDecoderPrefixes;
public static final List<String> whitelistedAdaptiveResolutionPrefixes;
static { static {
blacklistedDecoderPrefixes = new LinkedList<String>(); blacklistedDecoderPrefixes = new LinkedList<String>();
@ -62,6 +67,59 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
spsFixupNumRefFixupDecoderPrefixes.add("omx.TI"); spsFixupNumRefFixupDecoderPrefixes.add("omx.TI");
spsFixupNumRefFixupDecoderPrefixes.add("omx.qcom"); spsFixupNumRefFixupDecoderPrefixes.add("omx.qcom");
spsFixupNumRefFixupDecoderPrefixes.add("omx.sec"); spsFixupNumRefFixupDecoderPrefixes.add("omx.sec");
whitelistedAdaptiveResolutionPrefixes = new LinkedList<String>();
whitelistedAdaptiveResolutionPrefixes.add("omx.nvidia");
whitelistedAdaptiveResolutionPrefixes.add("omx.qcom");
whitelistedAdaptiveResolutionPrefixes.add("omx.sec");
whitelistedAdaptiveResolutionPrefixes.add("omx.TI");
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public MediaCodecDecoderRenderer() {
//dumpDecoders();
MediaCodecInfo decoder = findProbableSafeDecoder();
if (decoder == null) {
decoder = findFirstDecoder();
}
if (decoder == null) {
// This case is handled later in setup()
return;
}
decoderName = decoder.getName();
// Possibly enable adaptive playback on KitKat and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
if (decoder.getCapabilitiesForType("video/avc").
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
{
// This will make getCapabilities() return that adaptive playback is supported
LimeLog.info("Adaptive playback supported (FEATURE_AdaptivePlayback)");
adaptivePlayback = true;
}
} catch (Exception e) {
// Tolerate buggy codecs
}
}
if (!adaptivePlayback) {
if (isDecoderInList(whitelistedAdaptiveResolutionPrefixes, decoderName)) {
LimeLog.info("Adaptive playback supported (whitelist)");
adaptivePlayback = true;
}
}
needsSpsBitstreamFixup = isDecoderInList(spsFixupBitstreamFixupDecoderPrefixes, decoderName);
needsSpsNumRefFixup = isDecoderInList(spsFixupNumRefFixupDecoderPrefixes, decoderName);
if (needsSpsBitstreamFixup) {
LimeLog.info("Decoder "+decoderName+" needs SPS bitstream restrictions fixup");
}
if (needsSpsNumRefFixup) {
LimeLog.info("Decoder "+decoderName+" needs SPS ref num fixup");
}
} }
private static boolean isDecoderInList(List<String> decoderList, String decoderName) { private static boolean isDecoderInList(List<String> decoderList, String decoderName) {
@ -180,21 +238,14 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
return null; return null;
} }
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override @Override
public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) { public boolean setup(int width, int height, int redrawRate, Object renderTarget, int drFlags) {
//dumpDecoders(); if (decoderName == null) {
MediaCodecInfo decoder = findProbableSafeDecoder();
if (decoder == null) {
decoder = findFirstDecoder();
}
if (decoder == null) {
LimeLog.severe("No available hardware decoder!"); LimeLog.severe("No available hardware decoder!");
return false; return false;
} }
decoderName = decoder.getName();
// Codecs have been known to throw all sorts of crazy runtime exceptions // Codecs have been known to throw all sorts of crazy runtime exceptions
// due to implementation problems // due to implementation problems
try { try {
@ -203,16 +254,15 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
return false; return false;
} }
needsSpsBitstreamFixup = isDecoderInList(spsFixupBitstreamFixupDecoderPrefixes, decoder.getName()); MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
needsSpsNumRefFixup = isDecoderInList(spsFixupNumRefFixupDecoderPrefixes, decoder.getName());
if (needsSpsBitstreamFixup) { // Adaptive playback can also be enabled by the whitelist on pre-KitKat devices
LimeLog.info("Decoder "+decoder.getName()+" needs SPS bitstream restrictions fixup"); // so we don't fill these pre-KitKat
} if (adaptivePlayback && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (needsSpsNumRefFixup) { videoFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, width);
LimeLog.info("Decoder "+decoder.getName()+" needs SPS ref num fixup"); videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, height);
} }
MediaFormat videoFormat = MediaFormat.createVideoFormat("video/avc", width, height);
videoDecoder.configure(videoFormat, ((SurfaceHolder)renderTarget).getSurface(), null, 0); videoDecoder.configure(videoFormat, ((SurfaceHolder)renderTarget).getSurface(), null, 0);
videoDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT); videoDecoder.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
@ -366,63 +416,44 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
if (header.data[header.offset+4] == 0x67) { if (header.data[header.offset+4] == 0x67) {
numSpsIn++; numSpsIn++;
if ((needsSpsBitstreamFixup || needsSpsNumRefFixup)) { if (needsSpsBitstreamFixup || needsSpsNumRefFixup) {
byte last = header.data[header.length+header.offset-1]; ByteBuffer spsBuf = ByteBuffer.wrap(header.data);
// Skip to the start of the NALU data
spsBuf.position(header.offset+5);
SeqParameterSet sps = SeqParameterSet.read(spsBuf);
// TI OMAP4 requires a reference frame count of 1 to decode successfully // TI OMAP4 requires a reference frame count of 1 to decode successfully
if (needsSpsNumRefFixup) { if (needsSpsNumRefFixup) {
LimeLog.info("Fixing up num ref frames"); LimeLog.info("Fixing up num ref frames");
this.replace(header, 80, 9, new byte[] {0x40}, 3); sps.num_ref_frames = 1;
} }
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag // The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
// or max_dec_frame_buffering which increases decoding latency on Tegra. // or max_dec_frame_buffering which increases decoding latency on Tegra.
// We manually modify the SPS here to speed-up decoding if the decoder was flagged as needing it.
int spsLength;
if (needsSpsBitstreamFixup) { if (needsSpsBitstreamFixup) {
if (!needsSpsNumRefFixup) { LimeLog.info("Adding bitstream restrictions");
switch (header.length) {
case 26: sps.vuiParams.bitstreamRestriction = new VUIParameters.BitstreamRestriction();
LimeLog.info("Adding bitstream restrictions to SPS (26)"); sps.vuiParams.bitstreamRestriction.motion_vectors_over_pic_boundaries_flag = false;
buf.put(header.data, header.offset, 24); sps.vuiParams.bitstreamRestriction.max_bytes_per_pic_denom = 0;
buf.put((byte) 0x11); sps.vuiParams.bitstreamRestriction.max_bits_per_mb_denom = 0;
buf.put((byte) 0xe3); sps.vuiParams.bitstreamRestriction.log2_max_mv_length_horizontal = 16;
buf.put((byte) 0x06); sps.vuiParams.bitstreamRestriction.log2_max_mv_length_vertical = 16;
buf.put((byte) 0x50); sps.vuiParams.bitstreamRestriction.num_reorder_frames = 0;
spsLength = header.length + 2; sps.vuiParams.bitstreamRestriction.max_dec_frame_buffering = 1;
break;
case 27:
LimeLog.info("Adding bitstream restrictions to SPS (27)");
buf.put(header.data, header.offset, 25);
buf.put((byte) 0x04);
buf.put((byte) 0x78);
buf.put((byte) 0xc1);
buf.put((byte) 0x94);
spsLength = header.length + 2;
break;
default:
LimeLog.warning("Unknown SPS of length "+header.length);
buf.put(header.data, header.offset, header.length);
spsLength = header.length;
break;
}
}
else {
// Set bitstream restrictions to only buffer single frame
// (starts 9 bits before stop bit and 6 bits earlier because of the shortening above)
this.replace(header, header.length*8+Integer.numberOfLeadingZeros(last & - last)%8-9-6, 2, BITSTREAM_RESTRICTIONS, 3*8);
buf.put(header.data, header.offset, header.length);
spsLength = header.length;
}
}
else {
buf.put(header.data, header.offset, header.length);
spsLength = header.length;
} }
// Write the annex B header
buf.put(header.data, header.offset, 5);
// Write the modified SPS to the input buffer
sps.write(buf);
try { try {
videoDecoder.queueInputBuffer(inputIndex, videoDecoder.queueInputBuffer(inputIndex,
0, spsLength, 0, buf.position(),
currentTime * 1000, codecFlags); currentTime * 1000, codecFlags);
} catch (Exception e) { } catch (Exception e) {
throw new RendererException(this, e, buf, codecFlags); throw new RendererException(this, e, buf, codecFlags);
@ -453,86 +484,8 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
@Override @Override
public int getCapabilities() { public int getCapabilities() {
return 0; return adaptivePlayback ?
} VideoDecoderRenderer.CAPABILITY_ADAPTIVE_RESOLUTION : 0;
/**
* Replace bits in array
* @param source array in which bits should be replaced
* @param srcOffset offset in bits where replacement should take place
* @param srcLength length in bits of data that should be replaced
* @param data data array with the the replacement data
* @param dataLength length of replacement data in bits
*/
public void replace(ByteBufferDescriptor source, int srcOffset, int srcLength, byte[] data, int dataLength) {
//Add 7 to always round up
int length = (source.length*8-srcLength+dataLength+7)/8;
int bitOffset = srcOffset%8;
int byteOffset = srcOffset/8;
byte dest[] = null;
int offset = 0;
if (length>source.length) {
dest = new byte[length];
//Copy the first bytes
System.arraycopy(source.data, source.offset, dest, offset, byteOffset);
} else {
dest = source.data;
offset = source.offset;
}
int byteLength = (bitOffset+dataLength+7)/8;
int bitTrailing = 8 - (srcOffset+dataLength) % 8;
for (int i=0;i<byteLength;i++) {
byte result = 0;
if (i != 0)
result = (byte) (data[i-1] << 8-bitOffset);
else if (bitOffset > 0)
result = (byte) (source.data[byteOffset+source.offset] & (0xFF << 8-bitOffset));
if (i == 0 || i != byteLength-1) {
byte moved = (byte) ((data[i]&0xFF) >>> bitOffset);
result |= moved;
}
if (i == byteLength-1 && bitTrailing > 0) {
int sourceOffset = srcOffset+srcLength/8;
int bitMove = (dataLength-srcLength)%8;
if (bitMove<0) {
result |= (byte) (source.data[sourceOffset+source.offset] << -bitMove & (0xFF >>> bitTrailing));
result |= (byte) (source.data[sourceOffset+1+source.offset] << -bitMove & (0xFF >>> 8+bitMove));
} else {
byte moved = (byte) ((source.data[sourceOffset+source.offset]&0xFF) >>> bitOffset);
result |= moved;
}
}
dest[i+byteOffset+offset] = result;
}
//Source offset
byteOffset += srcLength/8;
bitOffset = (srcOffset+dataLength-srcLength)%8;
//Offset in destination
int destOffset = (srcOffset+dataLength)/8;
for (int i=1;i<source.length-byteOffset;i++) {
int diff = destOffset >= byteOffset-1?i:source.length-byteOffset-i;
byte result = 0;
result = (byte) (source.data[byteOffset+diff-1+source.offset] << 8-bitOffset);
byte moved = (byte) ((source.data[byteOffset+diff+source.offset]&0xFF) >>> bitOffset);
result ^= moved;
dest[diff+destOffset+offset] = result;
}
source.data = dest;
source.offset = offset;
source.length = length;
} }
@Override @Override

View File

@ -46,6 +46,8 @@ public class ComputerManagerService extends Service {
private ThreadPoolExecutor pollingPool; private ThreadPoolExecutor pollingPool;
private Timer pollingTimer; private Timer pollingTimer;
private ComputerManagerListener listener = null; private ComputerManagerListener listener = null;
private AtomicInteger activePolls = new AtomicInteger(0);
private boolean stopped;
private DiscoveryService.DiscoveryBinder discoveryBinder; private DiscoveryService.DiscoveryBinder discoveryBinder;
private ServiceConnection discoveryServiceConnection = new ServiceConnection() { private ServiceConnection discoveryServiceConnection = new ServiceConnection() {
@ -69,6 +71,9 @@ public class ComputerManagerService extends Service {
public class ComputerManagerBinder extends Binder { public class ComputerManagerBinder extends Binder {
public void startPolling(ComputerManagerListener listener) { public void startPolling(ComputerManagerListener listener) {
// Not stopped
stopped = false;
// Set the listener // Set the listener
ComputerManagerService.this.listener = listener; ComputerManagerService.this.listener = listener;
@ -92,6 +97,14 @@ public class ComputerManagerService extends Service {
} }
} }
public void waitForPollingStopped() {
while (activePolls.get() != 0) {
try {
Thread.sleep(250);
} catch (InterruptedException e) {}
}
}
public boolean addComputerBlocking(InetAddress addr) { public boolean addComputerBlocking(InetAddress addr) {
return ComputerManagerService.this.addComputerBlocking(addr); return ComputerManagerService.this.addComputerBlocking(addr);
} }
@ -116,6 +129,9 @@ public class ComputerManagerService extends Service {
@Override @Override
public boolean onUnbind(Intent intent) { public boolean onUnbind(Intent intent) {
// Stopped now
stopped = true;
// Stop mDNS autodiscovery // Stop mDNS autodiscovery
discoveryBinder.stopDiscovery(); discoveryBinder.stopDiscovery();
@ -385,15 +401,23 @@ public class ComputerManagerService extends Service {
public void run() { public void run() {
boolean newPc = (details.name == null); boolean newPc = (details.name == null);
if (stopped) {
return;
}
if (!getLocalDatabaseReference()) { if (!getLocalDatabaseReference()) {
return; return;
} }
activePolls.incrementAndGet();
// Poll the machine // Poll the machine
if (!doPollMachine(details)) { if (!doPollMachine(details)) {
details.state = ComputerDetails.State.OFFLINE; details.state = ComputerDetails.State.OFFLINE;
details.reachability = ComputerDetails.Reachability.OFFLINE; details.reachability = ComputerDetails.Reachability.OFFLINE;
} }
activePolls.decrementAndGet();
// If it's online, update our persistent state // If it's online, update our persistent state
if (details.state == ComputerDetails.State.ONLINE) { if (details.state == ComputerDetails.State.ONLINE) {