From b4a0f81edaee74adfcecf36ba670857b54e68e29 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 6 Jan 2014 22:52:11 -0600 Subject: [PATCH] Fixup bitstream_restriction_flag and max_dec_frame_buffering in the SPS to fix decoding latency issues on Tegra and the Raspberry Pi --- .../nvstream/av/video/VideoDepacketizer.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java b/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java index 8cfdba5a..904fd7e7 100644 --- a/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java +++ b/moonlight-common/src/com/limelight/nvstream/av/video/VideoDepacketizer.java @@ -41,6 +41,44 @@ public class VideoDepacketizer { { // This is the start of a new NAL if (avcNalDataChain != null && avcNalDataLength != 0) { + ByteBufferDescriptor header = avcNalDataChain.getFirst(); + + // 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 (at least) Tegra + // and Raspberry Pi. We manually modify the SPS here to speed-up decoding. + if (header.data[header.offset+4] == 0x67) { + // It's an SPS + ByteBufferDescriptor newSps; + switch (header.length) { + case 26: + System.out.println("Modifying SPS (26)"); + newSps = new ByteBufferDescriptor(new byte[header.length+2], 0, header.length+2); + System.arraycopy(header.data, header.offset, newSps.data, 0, 24); + newSps.data[24] = 0x11; + newSps.data[25] = (byte)0xe3; + newSps.data[26] = 0x06; + newSps.data[27] = 0x50; + break; + case 27: + System.out.println("Modifying SPS (27)"); + newSps = new ByteBufferDescriptor(new byte[header.length+2], 0, header.length+2); + System.arraycopy(header.data, header.offset, newSps.data, 0, 25); + newSps.data[25] = 0x04; + newSps.data[26] = 0x78; + newSps.data[27] = (byte) 0xc1; + newSps.data[28] = (byte) 0x94; + break; + default: + System.out.println("Unknown SPS of length "+header.length); + newSps = header; + break; + } + + avcNalDataChain.clear(); + avcNalDataChain.add(newSps); + avcNalDataLength = newSps.length; + } + // Construct the H264 decode unit DecodeUnit du = new DecodeUnit(DecodeUnit.TYPE_H264, avcNalDataChain, avcNalDataLength, 0); if (!decodedUnits.offer(du)) {