Updated config code for artifact-free 1080p60 streaming

This commit is contained in:
Cameron Gutman 2014-02-17 13:47:43 -05:00
parent 26809c4b6b
commit c93812179f
5 changed files with 274 additions and 115 deletions

View File

@ -0,0 +1,17 @@
package com.limelight.nvstream.control;
public class ByteConfigTuple extends ConfigTuple {
public static final short PAYLOAD_LENGTH = 1;
public byte payload;
public ByteConfigTuple(short packetType, byte payload) {
super(packetType, PAYLOAD_LENGTH);
this.payload = payload;
}
@Override
public byte[] payloadToWire() {
return new byte[] {payload};
}
}

View File

@ -2,103 +2,114 @@ package com.limelight.nvstream.control;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashSet;
import com.limelight.nvstream.StreamConfiguration;
public class Config {
public static final int[] UNKNOWN_CONFIG =
public static final ConfigTuple[] CONFIG_720_60 =
{
70151,
68291329,
1280,
68291584,
1280,
68291840,
15360,
68292096,
25600,
68292352,
2048,
68292608,
1024,
68289024,
262144,
17957632,
302055424,
134217729,
16777490,
70153,
68293120,
768000,
17961216,
303235072,
335609857,
838861842,
352321536,
1006634002,
369098752,
335545362,
385875968,
1042,
402653184,
134218770,
419430400,
167773202,
436207616,
855638290,
266779,
10000,
266780,
2000,
266781,
50,
266782,
3000,
266783,
2,
266794,
5000,
266795,
500,
266784,
75,
266785,
25,
266786,
10,
266787,
60,
266788,
30,
266789,
3,
266790,
1000,
266791,
5000,
266792,
5000,
266793,
5000,
70190,
68301063,
10240,
68301312,
6400,
68301568,
768000,
68299776,
768,
68300032,
2560,
68300544,
0,
34746368,
(int)0xFE000000
new IntConfigTuple((short)0x1206, 1),
new ByteConfigTuple((short)0x1207, (byte)1),
new IntConfigTuple((short)0x120b, 7),
new IntConfigTuple((short)0x120c, 7),
new IntConfigTuple((short)0x120d, 60),
new IntConfigTuple((short)0x120e, 100),
new IntConfigTuple((short)0x120f, 5),
new IntConfigTuple((short)0x1210, 4),
new IntConfigTuple((short)0x1202, 1024),
new ByteConfigTuple((short)0x1203, (byte)0),
new ByteConfigTuple((short)0x1201, (byte)0),
new ByteConfigTuple((short)0x1234, (byte)0),
new ByteConfigTuple((short)0x1248, (byte)0),
new ByteConfigTuple((short)0x1208, (byte)1),
new ByteConfigTuple((short)0x1209, (byte)0),
new IntConfigTuple((short)0x1212, 3000),
new IntConfigTuple((short)0x1238, 10000),
new ByteConfigTuple((short)0x1211, (byte)0),
new ByteConfigTuple((short)0x1213, (byte)1),
new IntConfigTuple((short)0x1214, 50),
new IntConfigTuple((short)0x1215, 60),
new IntConfigTuple((short)0x1216, 20),
new IntConfigTuple((short)0x1217, 0),
new IntConfigTuple((short)0x1218, 8),
new IntConfigTuple((short)0x1219, 10),
new IntConfigTuple((short)0x121a, 311),
new IntConfigTuple((short)0x121b, 10000),
new IntConfigTuple((short)0x121c, 2000),
new IntConfigTuple((short)0x121d, 50),
new IntConfigTuple((short)0x121e, 3000),
new IntConfigTuple((short)0x121f, 2),
new IntConfigTuple((short)0x122a, 5000),
new IntConfigTuple((short)0x122b, 500),
new IntConfigTuple((short)0x1220, 75),
new IntConfigTuple((short)0x1221, 25),
new IntConfigTuple((short)0x1222, 10),
new IntConfigTuple((short)0x1223, 60),
new IntConfigTuple((short)0x1224, 30),
new IntConfigTuple((short)0x1225, 3),
new IntConfigTuple((short)0x1226, 1000),
new IntConfigTuple((short)0x1227, 5000),
new IntConfigTuple((short)0x1228, 5000),
new IntConfigTuple((short)0x124e, 110),
new IntConfigTuple((short)0x1237, 10),
new IntConfigTuple((short)0x1236, 6),
new IntConfigTuple((short)0x1235, 4),
new IntConfigTuple((short)0x1242, 20000),
new IntConfigTuple((short)0x1244, 100),
new IntConfigTuple((short)0x1245, 1000),
new IntConfigTuple((short)0x1246, 720),
new IntConfigTuple((short)0x1247, 480),
new IntConfigTuple((short)0x1229, 5000),
new ByteConfigTuple((short)0x122e, (byte)7),
new IntConfigTuple((short)0x1231, 40),
new IntConfigTuple((short)0x1232, 25),
new IntConfigTuple((short)0x1233, 3000),
new IntConfigTuple((short)0x122c, 3),
new IntConfigTuple((short)0x122d, 10),
new IntConfigTuple((short)0x123b, 12),
new IntConfigTuple((short)0x123c, 3),
new IntConfigTuple((short)0x1249, 0),
new IntConfigTuple((short)0x124a, 4000),
new IntConfigTuple((short)0x124b, 5000),
new IntConfigTuple((short)0x124c, 6000),
new IntConfigTuple((short)0x124d, 1000),
new IntConfigTuple((short)0x122f, 0),
new ShortConfigTuple((short)0x1230, (short)0),
new IntConfigTuple((short)0x1239, 0),
new IntConfigTuple((short)0x123a, 0),
new IntConfigTuple((short)0x123d, 96000),
new IntConfigTuple((short)0x123e, 5),
new IntConfigTuple((short)0x123f, 1),
new IntConfigTuple((short)0x1243, 100)
};
public static final int CONFIG_SIZE = ((8 + UNKNOWN_CONFIG.length) * 4) + 3;
public static final ConfigTuple[] CONFIG_1080_30_DIFF =
{
new IntConfigTuple((short)0x120b, 10),
new IntConfigTuple((short)0x120c, 10),
new IntConfigTuple((short)0x121c, 4000),
new IntConfigTuple((short)0x1245, 3000),
new IntConfigTuple((short)0x1246, 1280),
new IntConfigTuple((short)0x1247, 720),
new IntConfigTuple((short)0x124a, 5000),
new IntConfigTuple((short)0x124c, 7000),
};
public static final ConfigTuple[] CONFIG_1080_60_DIFF =
{
new IntConfigTuple((short)0x120b, 30),
new IntConfigTuple((short)0x120c, 30),
new IntConfigTuple((short)0x120f, 4),
new IntConfigTuple((short)0x121b, 30000),
new IntConfigTuple((short)0x121c, 25000),
new IntConfigTuple((short)0x1245, 3000),
new IntConfigTuple((short)0x1246, 1280),
new IntConfigTuple((short)0x1247, 720),
new IntConfigTuple((short)0x124a, 5000),
new IntConfigTuple((short)0x124c, 7000),
};
private StreamConfiguration streamConfig;
@ -106,37 +117,69 @@ public class Config {
this.streamConfig = streamConfig;
}
private void updateSetWithConfig(HashSet<ConfigTuple> set, ConfigTuple[] config)
{
for (ConfigTuple tuple : config)
{
// Remove any existing tuple of this type
set.remove(tuple);
set.add(tuple);
}
}
private int getConfigOnWireSize(HashSet<ConfigTuple> tupleSet)
{
int size = 0;
for (ConfigTuple t : tupleSet)
{
size += ConfigTuple.HEADER_LENGTH + t.payloadLength;
}
return size;
}
private HashSet<ConfigTuple> generateTupleSet() {
HashSet<ConfigTuple> tupleSet = new HashSet<ConfigTuple>();
// Start with the initial config for 720p60
updateSetWithConfig(tupleSet, CONFIG_720_60);
if (streamConfig.getWidth() >= 1920 &&
streamConfig.getHeight() >= 1080)
{
if (streamConfig.getRefreshRate() >= 60)
{
// Update the initial set with the changed 1080p60 options
updateSetWithConfig(tupleSet, CONFIG_1080_60_DIFF);
}
else
{
// Update the initial set with the changed 1080p30 options
updateSetWithConfig(tupleSet, CONFIG_1080_30_DIFF);
}
}
tupleSet.add(new IntConfigTuple((short)0x1204, streamConfig.getWidth()));
tupleSet.add(new IntConfigTuple((short)0x1205, streamConfig.getHeight()));
tupleSet.add(new IntConfigTuple((short)0x120A, streamConfig.getRefreshRate()));
return tupleSet;
}
public byte[] toWire() {
ByteBuffer bb = ByteBuffer.allocate(CONFIG_SIZE).order(ByteOrder.LITTLE_ENDIAN);
HashSet<ConfigTuple> tupleSet = generateTupleSet();
ByteBuffer bb = ByteBuffer.allocate(getConfigOnWireSize(tupleSet) + 4).order(ByteOrder.LITTLE_ENDIAN);
// Width
bb.putShort((short) 0x1204);
bb.putShort((short) 0x0004);
bb.putInt(streamConfig.getWidth());
// Height
bb.putShort((short) 0x1205);
bb.putShort((short) 0x0004);
bb.putInt(streamConfig.getHeight());
// Unknown
bb.putShort((short) 0x1206);
bb.putShort((short) 0x0004);
bb.putInt(1);
// Refresh rate
bb.putShort((short) 0x120A);
bb.putShort((short) 0x0004);
bb.putInt(streamConfig.getRefreshRate());
// The rest are hardcoded
for (int i : UNKNOWN_CONFIG) {
bb.putInt(i);
for (ConfigTuple t : tupleSet)
{
bb.put(t.toWire());
}
// Config tail
bb.putShort((short) 0x0013);
bb.put((byte) 0x00);
bb.putShort((short) 0x13fe);
bb.putShort((short) 0x00);
return bb.array();
}

View File

@ -0,0 +1,53 @@
package com.limelight.nvstream.control;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public abstract class ConfigTuple {
public short packetType;
public short payloadLength;
public static final short HEADER_LENGTH = 4;
public ConfigTuple(short packetType, short payloadLength)
{
this.packetType = packetType;
this.payloadLength = payloadLength;
}
public abstract byte[] payloadToWire();
public byte[] toWire()
{
byte[] payload = payloadToWire();
ByteBuffer bb = ByteBuffer.allocate(HEADER_LENGTH + (payload != null ? payload.length : 0))
.order(ByteOrder.LITTLE_ENDIAN);
bb.putShort(packetType);
bb.putShort(payloadLength);
if (payload != null) {
bb.put(payload);
}
return bb.array();
}
@Override
public int hashCode()
{
return packetType;
}
@Override
public boolean equals(Object o)
{
// We only compare the packet types on purpose
if (o instanceof ConfigTuple) {
return ((ConfigTuple)o).packetType == packetType;
}
else {
return false;
}
}
}

View File

@ -0,0 +1,23 @@
package com.limelight.nvstream.control;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class IntConfigTuple extends ConfigTuple {
public static final short PAYLOAD_LENGTH = 4;
public int payload;
public IntConfigTuple(short packetType, int payload) {
super(packetType, PAYLOAD_LENGTH);
this.payload = payload;
}
@Override
public byte[] payloadToWire() {
ByteBuffer bb = ByteBuffer.allocate(PAYLOAD_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
bb.putInt(payload);
return bb.array();
}
}

View File

@ -0,0 +1,23 @@
package com.limelight.nvstream.control;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ShortConfigTuple extends ConfigTuple {
public static final short PAYLOAD_LENGTH = 2;
public short payload;
public ShortConfigTuple(short packetType, short payload) {
super(packetType, PAYLOAD_LENGTH);
this.payload = payload;
}
@Override
public byte[] payloadToWire() {
ByteBuffer bb = ByteBuffer.allocate(PAYLOAD_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
bb.putShort(payload);
return bb.array();
}
}