Compare commits

..

9 Commits

5 changed files with 184 additions and 44 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.limelight"
android:versionCode="9"
android:versionName="2.1.3" >
android:versionCode="11"
android:versionName="2.1.5" >
<uses-sdk
android:minSdkVersion="16"
+12
View File
@@ -0,0 +1,12 @@
{
"SupportedControllers" : {
"Gamepad" : {},
"Remote" : "false",
"SecondScreen" : {
"DPad" : "false",
"AnalogSticks" : "0",
"DigitalButtons" : "0",
"Mouse" : "false"
}
}
}
Binary file not shown.
+34 -4
View File
@@ -34,7 +34,7 @@ import android.view.WindowManager;
import android.widget.Toast;
public class Game extends Activity implements OnGenericMotionListener, OnTouchListener, NvConnectionListener {
public class Game extends Activity implements SurfaceHolder.Callback, OnGenericMotionListener, OnTouchListener, NvConnectionListener {
private int lastMouseX = Integer.MIN_VALUE;
private int lastMouseY = Integer.MIN_VALUE;
private int lastButtonState = 0;
@@ -52,6 +52,10 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
private NvConnection conn;
private SpinnerDialog spinner;
private boolean displayedFailureDialog = false;
private boolean connecting = false;
private boolean connected = false;
private int drFlags = 0;
public static final String PREFS_FILE_NAME = "gameprefs";
@@ -101,7 +105,6 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
// Read the stream preferences
SharedPreferences prefs = getSharedPreferences(PREFS_FILE_NAME, Context.MODE_MULTI_PROCESS);
int drFlags = 0;
switch (prefs.getInt(Game.DECODER_PREF_STRING, Game.DEFAULT_DECODER)) {
case Game.FORCE_SOFTWARE_DECODER:
drFlags |= VideoDecoderRenderer.FLAG_FORCE_SOFTWARE_DECODING;
@@ -130,8 +133,9 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
new StreamConfiguration(width, height, refreshRate));
keybTranslator = new KeyboardTranslator(conn);
controllerHandler = new ControllerHandler(conn);
conn.start(PlatformBinding.getDeviceName(), sv.getHolder(), drFlags,
PlatformBinding.getAudioRenderer(), new ConfigurableDecoderRenderer());
// The connection will be started when the surface gets created
sh.addCallback(this);
}
private void checkDataConnection()
@@ -420,6 +424,7 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
displayedFailureDialog = true;
Dialog.displayDialog(this, "Connection Error", "Starting "+stage.getName()+" failed", true);
conn.stop();
connecting = false;
}
}
@@ -430,6 +435,7 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
e.printStackTrace();
Dialog.displayDialog(this, "Connection Terminated", "The connection failed unexpectedly", true);
conn.stop();
connected = false;
}
}
@@ -438,6 +444,9 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
spinner.dismiss();
spinner = null;
connecting = false;
connected = true;
hideSystemUi();
}
@@ -460,4 +469,25 @@ public class Game extends Activity implements OnGenericMotionListener, OnTouchLi
}
});
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!connected && !connecting) {
connecting = true;
conn.start(PlatformBinding.getDeviceName(), holder, drFlags,
PlatformBinding.getAudioRenderer(), new ConfigurableDecoderRenderer());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (connected) {
conn.stop();
connected = false;
}
}
}
@@ -24,23 +24,27 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
private MediaCodec videoDecoder;
private Thread rendererThread;
private int redrawRate;
private boolean needsSpsFixup;
private boolean needsSpsBitstreamFixup;
private boolean needsSpsNumRefFixup;
private boolean fastInputQueueing;
public static final List<String> blacklistedDecoderPrefixes;
public static final List<String> spsFixupDecoderPrefixes;
public static final List<String> spsFixupBitsreamFixupDecoderPrefixes;
public static final List<String> spsFixupNumRefFixupDecoderPrefixes;
public static final List<String> fastInputQueueingPrefixes;
static {
blacklistedDecoderPrefixes = new LinkedList<String>();
// TI's decoder technically supports high profile but doesn't work for some reason
blacklistedDecoderPrefixes.add("omx.TI");
// Nothing here right now :)
}
static {
spsFixupDecoderPrefixes = new LinkedList<String>();
spsFixupDecoderPrefixes.add("omx.nvidia");
spsFixupBitsreamFixupDecoderPrefixes = new LinkedList<String>();
spsFixupBitsreamFixupDecoderPrefixes.add("omx.nvidia");
spsFixupNumRefFixupDecoderPrefixes = new LinkedList<String>();
spsFixupNumRefFixupDecoderPrefixes.add("omx.TI");
}
static {
@@ -128,9 +132,13 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
MediaCodecInfo safeDecoder = findSafeDecoder();
if (safeDecoder != null) {
videoDecoder = MediaCodec.createByCodecName(safeDecoder.getName());
needsSpsFixup = isDecoderInList(spsFixupDecoderPrefixes, safeDecoder.getName());
if (needsSpsFixup) {
LimeLog.info("Decoder "+safeDecoder.getName()+" needs SPS fixup");
needsSpsBitstreamFixup = isDecoderInList(spsFixupBitsreamFixupDecoderPrefixes, safeDecoder.getName());
needsSpsNumRefFixup = isDecoderInList(spsFixupNumRefFixupDecoderPrefixes, safeDecoder.getName());
if (needsSpsBitstreamFixup) {
LimeLog.info("Decoder "+safeDecoder.getName()+" needs SPS bitstream restrictions fixup");
}
if (needsSpsNumRefFixup) {
LimeLog.info("Decoder "+safeDecoder.getName()+" needs SPS ref num fixup");
}
fastInputQueueing = isDecoderInList(fastInputQueueingPrefixes, safeDecoder.getName());
if (fastInputQueueing) {
@@ -139,7 +147,8 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
}
else {
videoDecoder = MediaCodec.createDecoderByType("video/avc");
needsSpsFixup = false;
needsSpsBitstreamFixup = false;
needsSpsNumRefFixup = false;
fastInputQueueing = false;
}
@@ -256,39 +265,49 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
// Clear old input data
buf.clear();
// 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.
// We manually modify the SPS here to speed-up decoding if the decoder was flagged as needing it.
if (needsSpsFixup) {
if (needsSpsBitstreamFixup || needsSpsNumRefFixup) {
ByteBufferDescriptor header = decodeUnit.getBufferList().get(0);
// Check for SPS NALU type
if (header.data[header.offset+4] == 0x67) {
int spsLength;
// TI OMAP4 requires a reference frame count of 1 to decode successfully
if (needsSpsNumRefFixup) {
LimeLog.info("Fixing up num ref frames");
this.replace(header, 80, 9, new byte[] {0x40}, 3);
}
switch (header.length) {
case 26:
LimeLog.info("Modifying SPS (26)");
buf.put(header.data, header.offset, 24);
buf.put((byte) 0x11);
buf.put((byte) 0xe3);
buf.put((byte) 0x06);
buf.put((byte) 0x50);
spsLength = header.length + 2;
break;
case 27:
LimeLog.info("Modifying 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);
// 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.
// We manually modify the SPS here to speed-up decoding if the decoder was flagged as needing it.
int spsLength;
if (needsSpsBitstreamFixup) {
switch (header.length) {
case 26:
LimeLog.info("Adding bitstream restrictions to SPS (26)");
buf.put(header.data, header.offset, 24);
buf.put((byte) 0x11);
buf.put((byte) 0xe3);
buf.put((byte) 0x06);
buf.put((byte) 0x50);
spsLength = header.length + 2;
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 {
buf.put(header.data, header.offset, header.length);
spsLength = header.length;
break;
}
videoDecoder.queueInputBuffer(inputIndex,
@@ -316,4 +335,83 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
public int getCapabilities() {
return fastInputQueueing ? VideoDecoderRenderer.CAPABILITY_DIRECT_SUBMIT : 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;
}
}