diff --git a/LuaScripts/NALParser.lua b/LuaScripts/NALParser.lua new file mode 100644 index 00000000..c622215d --- /dev/null +++ b/LuaScripts/NALParser.lua @@ -0,0 +1,62 @@ +-- H264 NAL Parser +-- Version: 1.0 +-- Cameron Gutman + +-- NAL header +local nal_start = ProtoField.bytes("nal.start", "H264 NAL Start Sequence") -- 4 Byte Start +local nal_type = ProtoField.uint8("nal.type", "H264 NAL Type") -- 1 byte NAL type +local nal_data = ProtoField.bytes("nal.data", "H264 NAL Data") -- variable byte NAL data + +p_h264raw = Proto("h264raw", "H264 Raw NAL Parser") +p_h264raw.fields = { + nal_start, + nal_type, + nal_data + } + +function p_h264raw.dissector(buf, pkt, root) + pkt.cols.protocol = p_h264raw.name + subtree = root:add(p_h264raw, buf(0)) + + local i = 0 + local data_start = -1 + while i < buf:len do + -- Make sure we have a potential start sequence and type + if buf:len() - i < 5 then + -- We need more data + pkt.desegment_len = DESEGMENT_ONE_MORE_SEGMENT + pkt.desegment_offset = 0 + return + end + + -- Check for start sequence + start = buf(i, 4):uint() + if start == 1 then + if data_start ~= -1 then + -- End the last NAL + subtree:add(nal_data, buf(data_start, i-data_start)) + end + -- This is the start of a NAL + subtree:add(nal_start, buf(i, 4)) + i = i + 4 + -- Next byte is NAL type + subtree:add(nal_type, buf(i, 1), buf(i, 1):uint8()) + i = i + 1 + -- Data begins here + data_start = i + else + -- This must be a data byte + i = i + 1 + end + end +end + +function p_h264raw.init() +end + + +local udp_dissector_table = DissectorTable.get("rtp.pt") +udp_dissector_table:add(96, p_h264raw) + + + diff --git a/LuaScripts/NVStreamVideoPacket.lua b/LuaScripts/NVStreamVideoPacket.lua new file mode 100644 index 00000000..c1b40b57 --- /dev/null +++ b/LuaScripts/NVStreamVideoPacket.lua @@ -0,0 +1,89 @@ +-- Nvidia Streaming Video Packet Dissector +-- Version: 1.0 +-- Diego Waxemberg + +-- video header +local nvHeader_frame = ProtoField.uint32("nv.frame", "Frame", base.HEX) -- 4 bytes +local nvHeader_pindex = ProtoField.uint16("nv.pindex", "Packet Index", base.HEX) -- 2 bytes +local nvHeader_empty = ProtoField.uint16("nv.empty", "Empty?", base.HEX) -- 2 bytes +local nvHeader_pframe = ProtoField.uint16("nv.pframe", "Packets in Frame", base.HEX) -- 2 bytes +local nvHeader_garbage = ProtoField.bytes("nv.garbage", "Garbage") -- 6 bytes +local nvHeader_length = ProtoField.uint16("nv.length", "Length", base.HEX) -- 2 bytes +local nvHeader_moregarbage = ProtoField.bytes("nv.moregarbage", "More Garbage") --23 bytes +local nvHeader_start = ProtoField.uint32("nv.start", "Start", base.HEX) -- 4 bytes + +-- video data +local nvVideo_data = ProtoField.bytes("nv.data", "Data") -- rest + +p_nv = Proto("nv", "Nvidia Video Stream Protocol") +p_nv.fields = { + nvHeader_frame, + nvHeader_pindex, + nvHeader_empty, + nvHeader_pframe, + nvHeader_garbage, + nvHeader_length, + nvHeader_moregarbage, + nvHeader_start, + nvVideo_data + } + +function p_nv.dissector(buf, pkt, root) + pkt.cols.protocol = p_nv.name + subtree = root:add(p_nv, buf(0)) + + i = 0 + -- frame + frame = buf(i, 4):le_uint() + subtree:add(nvHeader_frame, buf(i, 4), frame) + i = i + 4 + + --pindex + pindex = buf(i, 2):le_uint() + subtree:add(nvHeader_pindex, buf(i, 2), pindex) + i = i + 2 + + --empty + empty = buf(i, 2):le_uint() + subtree:add(nvHeader_empty, buf(i, 2), empty) + i = i + 2 + + --pframe + pframe = buf(i, 2):le_uint() + subtree:add(nvHeader_pframe, buf(i, 2), pframe) + i = i + 2 + + -- garbage + garbage = buf(i, 6):bytes() + subtree:add(nvHeader_garbage, buf(i, 6)) + i = i + 6 + + -- length + length = buf(i, 2):le_uint() + subtree:add(nvHeader_length, buf(i, 2), length) + i = i + 2 + + -- moregarbage + moregarbage = buf(i, 23):bytes() + subtree:add(nvHeader_moregarbage, buf(i, 23)) + i = i + 23 + + -- start + start = buf(i, 4):uint() + subtree:add(nvHeader_start, buf(i, 4), start) + i = i + 4 + + -- data + data = buf(i, buf:len()-i):bytes() + subtree:add(nvVideo_data, buf(i, buf:len()-i)) +end + +function p_nv.init() +end + + +local udp_dissector_table = DissectorTable.get("rtp.pt") +udp_dissector_table:add(96, p_nv) + + + diff --git a/LuaScripts/gridctl.lua b/LuaScripts/gridctl.lua new file mode 100644 index 00000000..a14bd053 --- /dev/null +++ b/LuaScripts/gridctl.lua @@ -0,0 +1,86 @@ +local pf_type = ProtoField.uint16("gridctl.type", "Packet Type", base.HEX) +local pf_paylen = ProtoField.uint32("gridctl.paylen", "Payload Length", base.DEC) +local pf_payload = ProtoField.bytes("gridctl.payload", "Payload bytes") +local pf_payload32 = ProtoField.uint32("gridctl.payload32", "Payload as 32-bit LE integer", base.DEC) +local pf_payload16 = ProtoField.uint16("gridctl.payload16", "Payload as 16-bit LE integer", base.HEX) +local pf_response = ProtoField.uint16("gridctl.response", "Response code", base.HEX) +local pf_origtype = ProtoField.uint16("gridctl.origtype", "Original request type", base.HEX) + +p_gridctl = Proto ("GridCtl", "Nvidia GRID Control Protocol") + +p_gridctl.fields = { + pf_type, + pf_paylen, + pf_payload, + pf_payload16, + pf_payload32, + pf_response, + pf_origtype +} + +function p_gridctl.dissector(buf, pkt, root) + pkt.cols.protocol = p_gridctl.name + + subtree = root:add(p_gridctl, buf(0)) + + -- We can have multiple GRID control packets in one TCP datagram + i = 0 + while i < buf:len() do + -- Make sure we have a full header + if buf:len() - i < 4 then + -- We need more data + pkt.desegment_len = DESEGMENT_ONE_MORE_SEGMENT + pkt.desegment_offset = 0 + end + + -- Read the packet type field + ptype = buf(i, 2):le_uint() + subtree:add(pf_type, buf(i, 2), ptype) + i = i + 2 + + -- Read the payload length field + paylen = buf(i, 2):le_uint() + subtree:add(pf_paylen, buf(i, 2), paylen) + i = i + 2 + + -- Make sure we have the full payload + if buf:len() - i < paylen then + -- We need more data + pkt.desegment_len = DESEGMENT_ONE_MORE_SEGMENT + pkt.desegment_offset = 0 + end + + -- Decode responses differently + if ptype == 0x0204 then + origtype = buf(i, 2):le_uint() + subtree:add(pf_origtype, buf(i, 2), origtype) + i = i + 2 + response = buf(i, 2):le_uint() + subtree:add(pf_response, buf(i, 2), response) + i = i + 2 + else + if paylen == 4 then + -- Display the payload as a uint32 (LE) + payload32 = buf(i, 4):le_uint() + subtree:add(pf_payload32, buf(i, 4), payload32) + elseif paylen == 2 then + -- Display the payload as a uint16 (LE) + payload16 = buf(i, 2):le_uint() + subtree:add(pf_payload16, buf(i, 2), payload16) + elseif paylen ~= 0 then + subtree:add(pf_payload, buf(i, paylen)) + end + i = i + paylen + end + + if i ~= buf:len() then + subtree:add("") + end + end +end + +function p_gridctl.init() +end + +local tcp_dissector_table = DissectorTable.get("tcp.port") +tcp_dissector_table:add(47995, p_gridctl) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..78fa612a --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +#Limelight + +Limelight is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield. +We reverse engineered the Shield streaming software and created a version that can be run on any Android device. + +Limelight will allow you to stream your full collection of games from your Windows PC to your Android device, +whether in your own home or over the internet. + +[Limelight-pc](https://github.com/limelight-stream/limelight-pc) is also currently in development for Windows, OS X and Linux. Versions for [iOS](https://github.com/limelight-stream/limelight-ios) and [Windows and Windows Phone](https://github.com/limelight-stream/limelight-windows) are also in development. + +##Features + +* Streams any of your games from your PC to your Android device +* Full gamepad support for MOGA, Xbox 360, PS3, OUYA, and Shield +* Automatically finds GameStream-compatible PCs on your network + +##Features in development +* Keyboard input + +##Installation + +* Download and install Limelight for Android from +[Google Play](https://play.google.com/store/apps/details?id=com.limelight) +* Download [GeForce Experience](http://www.geforce.com/geforce-experience) and install on your Windows PC + +##Requirements + +* [GameStream compatible](http://shield.nvidia.com/play-pc-games/) computer with GTX 600/700 series GPU +* Android device running 4.1 (Jelly Bean) or higher +* High-end wireless router (802.11n dual-band recommended) +* Exynos/Snapdragon SoC __OR__ Quad-Core 1.4 GHz Cortex-A9 or higher (Tegra 3) + +##Usage + +* Turn on GameStream in the GFE settings +* If you are connecting from outside the same network, turn on internet + streaming +* When on the same network as your PC, open Limelight and tap on your PC in the list +* Accept the pairing confirmation on your PC +* Tap your PC again to view the list of apps to stream +* Play games! + +##Contribute + +This project is being actively developed at [XDA Developers](http://forum.xda-developers.com/showthread.php?t=2505510) + +1. Fork us +2. Write code +3. Send Pull Requests + +Check out our [website](http://limelight-stream.com) for project links and information. + +##Authors + +* [Cameron Gutman](https://github.com/cgutman) +* [Diego Waxemberg](https://github.com/dwaxemberg) +* [Aaron Neyer](https://github.com/Aaronneyer) +* [Andrew Hennessy](https://github.com/yetanothername) + +Limelight is the work of students at [Case Western](http://case.edu) and was +started as a project at [MHacks](http://mhacks.org). diff --git a/decoder-errata.txt b/decoder-errata.txt new file mode 100644 index 00000000..d761f161 --- /dev/null +++ b/decoder-errata.txt @@ -0,0 +1,19 @@ +This file serves to document some of the decoder errata when using MediaCodec hardware decoders on certain devices. + +1. num_ref_frames is set to 16 by NVENC which causes decoders to allocate 16+ buffers. This can cause an error or lag on some devices. + - Affected decoders: TI OMAP4, Allwinner A20 + +2. Some decoders have a huge per-frame latency with the unmodified SPS sent from NVENC. Setting max_dec_frame_buffering fixes this latency issue. + - Affected decoders: NVIDIA Tegra 3 and 4 + +3. Some decoders strictly require that you pass BUFFER_FLAG_CODEC_CONFIG and crash upon the IDR frame if you don't + - Affected decoders: TI OMAP4 + +4. Some decoders require num_ref_frames=1 and max_dec_frame_buffering=1 to avoid crashing on SPS or first I-frame + - Affected decoders: Qualcomm in GS3 on 4.3+, Exynos 4 at 1080p only + +5. Some decoders will hang if max_dec_frame_buffering is not present + - Affected decoders: MediaTek decoder in Fire HD 7 (2014) + +6. Some decoders will hang if max_dec_frame_buffering IS present + - Affected decoders: Exynos 5 in Galaxy Note 10.1 (2014) \ No newline at end of file